diff options
author | Parménides GV <parmegv@sdf.org> | 2014-04-07 20:43:34 +0200 |
---|---|---|
committer | Parménides GV <parmegv@sdf.org> | 2014-04-08 11:43:27 +0200 |
commit | c206a91d320995f37f8abb33188bfd384249da3d (patch) | |
tree | 10a7d8a9dd7f24437ac4851b8d01edbd5dd3ee3b /src/se/leap/bitmaskclient | |
parent | 910b0e1746ab3f63e63808b198ad51fec5b635e5 (diff) |
Next step: compile jni sources correctly.
Diffstat (limited to 'src/se/leap/bitmaskclient')
19 files changed, 0 insertions, 5065 deletions
diff --git a/src/se/leap/bitmaskclient/AboutActivity.java b/src/se/leap/bitmaskclient/AboutActivity.java deleted file mode 100644 index 6d025422..00000000 --- a/src/se/leap/bitmaskclient/AboutActivity.java +++ /dev/null @@ -1,40 +0,0 @@ -package se.leap.bitmaskclient; - -import android.app.Activity; -import android.app.Fragment; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import se.leap.bitmaskclient.R; - -public class AboutActivity extends Activity { - - final public static String TAG = "aboutFragment"; - final public static int VIEWED = 0; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.about); - TextView ver = (TextView) findViewById(R.id.version); - - String version; - String name="Openvpn"; - try { - PackageInfo packageinfo = getPackageManager().getPackageInfo(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)); - setResult(VIEWED); - } - -} diff --git a/src/se/leap/bitmaskclient/ConfigHelper.java b/src/se/leap/bitmaskclient/ConfigHelper.java deleted file mode 100644 index a8bd3b7a..00000000 --- a/src/se/leap/bitmaskclient/ConfigHelper.java +++ /dev/null @@ -1,194 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -package se.leap.bitmaskclient; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.io.InputStream; -import java.security.KeyFactory; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; - -import org.json.JSONException; -import org.json.JSONObject; - -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Base64; - -/** - * Stores constants, and implements auxiliary methods used across all LEAP Android classes. - * - * @author parmegv - * @author MeanderingCode - * - */ -public class ConfigHelper { - private static KeyStore keystore_trusted; - - final public static String NG_1024 = - "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; - final public static BigInteger G = new BigInteger("2"); - - public static boolean checkErroneousDownload(String downloaded_string) { - try { - if(new JSONObject(downloaded_string).has(ProviderAPI.ERRORS) || downloaded_string.isEmpty()) { - return true; - } else { - return false; - } - } catch(JSONException e) { - return false; - } - } - - /** - * 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; - } - - public static X509Certificate parseX509CertificateFromString(String certificate_string) { - java.security.cert.Certificate certificate = null; - CertificateFactory cf; - try { - cf = CertificateFactory.getInstance("X.509"); - - certificate_string = certificate_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); - byte[] cert_bytes = Base64.decode(certificate_string, Base64.DEFAULT); - InputStream caInput = new ByteArrayInputStream(cert_bytes); - try { - certificate = cf.generateCertificate(caInput); - System.out.println("ca=" + ((X509Certificate) certificate).getSubjectDN()); - } finally { - caInput.close(); - } - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - return null; - } - - return (X509Certificate) certificate; - } - - protected static RSAPrivateKey parseRsaKeyFromString(String RsaKeyString) { - RSAPrivateKey key = null; - try { - KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); - - RsaKeyString = RsaKeyString.replaceFirst("-----BEGIN RSA PRIVATE KEY-----", "").replaceFirst("-----END RSA PRIVATE KEY-----", ""); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec( Base64.decode(RsaKeyString, Base64.DEFAULT) ); - key = (RSAPrivateKey) kf.generatePrivate(keySpec); - } catch (InvalidKeySpecException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } catch (NoSuchProviderException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - - return key; - } - - /** - * Adds a new X509 certificate given its input stream and its provider name - * @param provider used to store the certificate in the keystore - * @param inputStream from which X509 certificate must be generated. - */ - public static void addTrustedCertificate(String provider, InputStream inputStream) { - CertificateFactory cf; - try { - cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = - (X509Certificate)cf.generateCertificate(inputStream); - keystore_trusted.setCertificateEntry(provider, cert); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * Adds a new X509 certificate given in its string from and using its provider name - * @param provider used to store the certificate in the keystore - * @param certificate - */ - public static void addTrustedCertificate(String provider, String certificate) { - - try { - X509Certificate cert = ConfigHelper.parseX509CertificateFromString(certificate); - if(keystore_trusted == null) { - keystore_trusted = KeyStore.getInstance("BKS"); - keystore_trusted.load(null); - } - keystore_trusted.setCertificateEntry(provider, cert); - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * @return class wide keystore - */ - public static KeyStore getKeystore() { - return keystore_trusted; - } -} diff --git a/src/se/leap/bitmaskclient/ConfigurationWizard.java b/src/se/leap/bitmaskclient/ConfigurationWizard.java deleted file mode 100644 index f0aac40b..00000000 --- a/src/se/leap/bitmaskclient/ConfigurationWizard.java +++ /dev/null @@ -1,581 +0,0 @@ -/**
- * Copyright (c) 2013 LEAP Encryption Access Project and contributers
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package se.leap.bitmaskclient;
-
- - - -
-
-import android.app.Activity;
-import android.app.DialogFragment;
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.res.AssetManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.Display;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View.MeasureSpec;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.ProgressBar;
-import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-import java.io.IOException;
-import java.net.MalformedURLException; -import java.net.URL; -import java.util.Iterator;
-import org.json.JSONException;
-import org.json.JSONObject;
-import se.leap.bitmaskclient.DownloadFailedDialog.DownloadFailedDialogInterface; -import se.leap.bitmaskclient.NewProviderDialog.NewProviderDialogInterface; -import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver; -import se.leap.bitmaskclient.ProviderDetailFragment.ProviderDetailFragmentInterface; -import se.leap.bitmaskclient.ProviderListContent.ProviderItem; -import se.leap.bitmaskclient.R; -
-/**
- * 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, NewProviderDialogInterface, ProviderDetailFragmentInterface, DownloadFailedDialogInterface, Receiver {
-
- private ProgressBar mProgressBar;
- private TextView progressbar_description;
- private ProviderListFragment provider_list_fragment;
- private Intent mConfigState = new Intent();
-
- final public static String TAG = "se.leap.bitmaskclient.ConfigurationWizard";
- final public static String TYPE_OF_CERTIFICATE = "type_of_certificate";
- final public static String ANON_CERTIFICATE = "anon_certificate";
- final public static String AUTHED_CERTIFICATE = "authed_certificate";
-
- final protected static String PROVIDER_SET = "PROVIDER SET";
- final protected static String SERVICES_RETRIEVED = "SERVICES RETRIEVED";
-
- public ProviderAPIResultReceiver providerAPI_result_receiver;
- private ProviderAPIBroadcastReceiver_Update providerAPI_broadcast_receiver_update; - - private static SharedPreferences preferences;
- private static boolean setting_up_provider = false; -
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- preferences = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE);
-
- setContentView(R.layout.configuration_wizard_activity);
- mProgressBar = (ProgressBar) findViewById(R.id.progressbar_configuration_wizard);
- mProgressBar.setVisibility(ProgressBar.INVISIBLE);
- progressbar_description = (TextView) findViewById(R.id.progressbar_description);
- progressbar_description.setVisibility(TextView.INVISIBLE);
- providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
- providerAPI_result_receiver.setReceiver(this);
- providerAPI_broadcast_receiver_update = new ProviderAPIBroadcastReceiver_Update();
- IntentFilter update_intent_filter = new IntentFilter(ProviderAPI.UPDATE_PROGRESSBAR);
- update_intent_filter.addCategory(Intent.CATEGORY_DEFAULT);
- registerReceiver(providerAPI_broadcast_receiver_update, update_intent_filter);
-
- 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)
- provider_list_fragment = ProviderListFragment.newInstance();
- Bundle arguments = new Bundle();
- int configuration_wizard_request_code = getIntent().getIntExtra(Dashboard.REQUEST_CODE, -1);
- if(configuration_wizard_request_code == Dashboard.SWITCH_PROVIDER) {
- arguments.putBoolean(ProviderListFragment.SHOW_ALL_PROVIDERS, true);
- }
- provider_list_fragment.setArguments(arguments);
-
- FragmentManager fragmentManager = getFragmentManager();
- fragmentManager.beginTransaction()
- .replace(R.id.configuration_wizard_layout, provider_list_fragment, ProviderListFragment.TAG)
- .commit();
- }
-
- // TODO: If exposing deep links into your app, handle intents here.
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- unregisterReceiver(providerAPI_broadcast_receiver_update);
- }
-
- public void refreshProviderList(int top_padding) {
- ProviderListFragment new_provider_list_fragment = new ProviderListFragment();
- Bundle top_padding_bundle = new Bundle();
- top_padding_bundle.putInt(ProviderListFragment.TOP_PADDING, top_padding);
- new_provider_list_fragment.setArguments(top_padding_bundle);
-
- FragmentManager fragmentManager = getFragmentManager();
- fragmentManager.beginTransaction()
- .replace(R.id.configuration_wizard_layout, new_provider_list_fragment, ProviderListFragment.TAG)
- .commit();
- }
-
- @Override
- public void onReceiveResult(int resultCode, Bundle resultData) {
- if(resultCode == ProviderAPI.PROVIDER_OK) {
- mConfigState.setAction(PROVIDER_SET);
-
- if (preferences.getBoolean(EIP.ALLOWED_ANON, false)){
- mConfigState.putExtra(SERVICES_RETRIEVED, true);
- downloadAnonCert();
- } else {
- mProgressBar.incrementProgressBy(1);
- mProgressBar.setVisibility(ProgressBar.GONE);
- progressbar_description.setVisibility(TextView.GONE);
- setResult(RESULT_OK); - showProviderDetails(getCurrentFocus());
- } - } else if(resultCode == ProviderAPI.PROVIDER_NOK) {
- //refreshProviderList(0); - String reason_to_fail = resultData.getString(ProviderAPI.ERRORS);
- showDownloadFailedDialog(getCurrentFocus(), reason_to_fail);
- mProgressBar.setVisibility(ProgressBar.GONE);
- progressbar_description.setVisibility(TextView.GONE); - preferences.edit().remove(Provider.KEY).commit();
- setting_up_provider = false; - setResult(RESULT_CANCELED, mConfigState);
- }
- else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) {
- mProgressBar.incrementProgressBy(1);
- mProgressBar.setVisibility(ProgressBar.GONE);
- progressbar_description.setVisibility(TextView.GONE);
- //refreshProviderList(0);
- setResult(RESULT_OK);
- showProviderDetails(getCurrentFocus());
- } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
- //refreshProviderList(0);
- mProgressBar.setVisibility(ProgressBar.GONE);
- progressbar_description.setVisibility(TextView.GONE);
- //Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_certificate_message, Toast.LENGTH_LONG).show();
- setResult(RESULT_CANCELED, mConfigState);
- } else if(resultCode == AboutActivity.VIEWED) { - // Do nothing, right now - // I need this for CW to wait for the About activity to end before going back to Dashboard. - } - }
-
- /**
- * 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
- // resetOldConnection();
- ProviderItem selected_provider = getProvider(id);
- int provider_index = getProviderIndex(id);
- - - startProgressBar(provider_index+1); - provider_list_fragment.hideAllBut(provider_index); - - boolean danger_on = true; - if(preferences.contains(ProviderItem.DANGER_ON)) - danger_on = preferences.getBoolean(ProviderItem.DANGER_ON, false); - setUpProvider(selected_provider.providerMainUrl(), danger_on); - }
-
- @Override
- public void onBackPressed() {
- if(setting_up_provider) { - stopSettingUpProvider(); - } else {
- usualBackButton(); - } - } -
- private void stopSettingUpProvider() {
- ProviderAPI.stop();
- mProgressBar.setVisibility(ProgressBar.GONE);
- mProgressBar.setProgress(0);
- progressbar_description.setVisibility(TextView.GONE);
- getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).edit().remove(Provider.KEY).commit();
- setting_up_provider = false;
- showAllProviders(); - }
-
- private void usualBackButton() {
- try {
- boolean is_provider_set_up = new JSONObject(preferences.getString(Provider.KEY, "no provider")) != null ? true : false;
- boolean is_provider_set_up_truly = new JSONObject(preferences.getString(Provider.KEY, "no provider")).length() != 0 ? true : false;
- if(!is_provider_set_up || !is_provider_set_up_truly) {
- askDashboardToQuitApp();
- } else {
- setResult(RESULT_OK);
- }
- } catch (JSONException e) {
- askDashboardToQuitApp();
- super.onBackPressed();
- e.printStackTrace();
- }
- super.onBackPressed();
- }
- private void askDashboardToQuitApp() {
- Intent ask_quit = new Intent();
- ask_quit.putExtra(Dashboard.ACTION_QUIT, Dashboard.ACTION_QUIT);
- setResult(RESULT_CANCELED, ask_quit);
- }
-
- private ProviderItem getProvider(String name) {
- Iterator<ProviderItem> providers_iterator = ProviderListContent.ITEMS.iterator();
- while(providers_iterator.hasNext()) {
- ProviderItem provider = providers_iterator.next();
- if(provider.name().equalsIgnoreCase(name)) {
- return provider;
- }
- }
- return null;
- }
-
- private String getId(String provider_main_url_string) { - try { - URL provider_url = new URL(provider_main_url_string); - URL aux_provider_url; - Iterator<ProviderItem> providers_iterator = ProviderListContent.ITEMS.iterator(); - while(providers_iterator.hasNext()) { - ProviderItem provider = providers_iterator.next(); - aux_provider_url = new URL(provider.providerMainUrl()); - if(isSameURL(provider_url, aux_provider_url)) { - return provider.name(); - } - } - } catch (MalformedURLException e) { - e.printStackTrace(); - } - return ""; - }
- - /** - * Checks, whether 2 urls are pointing to the same location. - * - * @param url a url - * @param baseUrl an other url, that should be compared. - * @return true, if the urls point to the same host and port and use the - * same protocol, false otherwise. - */ - private boolean isSameURL(final URL url, final URL baseUrl) { - if (!url.getProtocol().equals(baseUrl.getProtocol())) { - return false; - } - if (!url.getHost().equals(baseUrl.getHost())) { - return false; - } - if (url.getPort() != baseUrl.getPort()) { - return false; - } - return true; - } -
- private void startProgressBar() {
- mProgressBar.setVisibility(ProgressBar.VISIBLE);
- mProgressBar.setProgress(0);
- mProgressBar.setMax(3);
- }
-
- private void startProgressBar(int list_item_index) {
- mProgressBar.setVisibility(ProgressBar.VISIBLE);
- progressbar_description.setVisibility(TextView.VISIBLE);
- mProgressBar.setProgress(0);
- mProgressBar.setMax(3);
- int measured_height = listItemHeight(list_item_index);
- mProgressBar.setTranslationY(measured_height);
- progressbar_description.setTranslationY(measured_height + mProgressBar.getHeight());
- }
-
- private int getProviderIndex(String id) {
- int index = 0;
- Iterator<ProviderItem> providers_iterator = ProviderListContent.ITEMS.iterator();
- while(providers_iterator.hasNext()) {
- ProviderItem provider = providers_iterator.next();
- if(provider.name().equalsIgnoreCase(id)) {
- break;
- } else index++; - }
- return index;
- }
-
- private int listItemHeight(int list_item_index) {
- ListView provider_list_view = (ListView)findViewById(android.R.id.list);
- ListAdapter provider_list_adapter = provider_list_view.getAdapter();
- View listItem = provider_list_adapter.getView(0, null, provider_list_view);
- listItem.setLayoutParams(new RelativeLayout.LayoutParams(
- RelativeLayout.LayoutParams.WRAP_CONTENT,
- RelativeLayout.LayoutParams.WRAP_CONTENT));
- WindowManager wm = (WindowManager) getApplicationContext()
- .getSystemService(Context.WINDOW_SERVICE);
- Display display = wm.getDefaultDisplay();
- int screenWidth = display.getWidth(); // deprecated
-
- int listViewWidth = screenWidth - 10 - 10;
- int widthSpec = MeasureSpec.makeMeasureSpec(listViewWidth,
- MeasureSpec.AT_MOST);
- listItem.measure(widthSpec, 0);
-
- return listItem.getMeasuredHeight();
-}
-
- /**
- * Loads providers data from url file contained in the project
- * @return true if the file was read correctly
- */
- private boolean loadPreseededProviders() {
- boolean loaded_preseeded_providers = false;
- AssetManager asset_manager = getAssets();
- String[] urls_filepaths = null;
- try {
- String url_files_folder = "urls";
- //TODO Put that folder in a better place (also inside the "for")
- urls_filepaths = asset_manager.list(url_files_folder);
- String provider_name = "";
- for(String url_filepath : urls_filepaths)
- {
- boolean custom = false;
- provider_name = url_filepath.subSequence(0, url_filepath.indexOf(".")).toString();
- if(ProviderListContent.ITEMS.isEmpty()) //TODO I have to implement a way of checking if a provider new or is already present in that ITEMS list
- ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath))); - loaded_preseeded_providers = true;
- }
- } catch (IOException e) {
- loaded_preseeded_providers = false;
- }
-
- return loaded_preseeded_providers;
- }
-
- /**
- * Asks ProviderAPI to download an anonymous (anon) VPN certificate.
- */
- private void downloadAnonCert() {
- Intent provider_API_command = new Intent(this, ProviderAPI.class);
-
- Bundle parameters = new Bundle();
-
- parameters.putString(TYPE_OF_CERTIFICATE, ANON_CERTIFICATE);
-
- provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE);
- provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters);
- provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver);
-
- startService(provider_API_command);
- }
-
- /**
- * Open the new provider dialog
- */
- public void addAndSelectNewProvider() {
- FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction();
- Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(NewProviderDialog.TAG);
- if (previous_new_provider_dialog != null) {
- fragment_transaction.remove(previous_new_provider_dialog);
- }
- fragment_transaction.addToBackStack(null);
-
- DialogFragment newFragment = NewProviderDialog.newInstance();
- newFragment.show(fragment_transaction, NewProviderDialog.TAG);
- }
-
- /**
- * Open the new provider dialog with data
- */
- public void addAndSelectNewProvider(String main_url, boolean danger_on) {
- FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction();
- Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(NewProviderDialog.TAG);
- if (previous_new_provider_dialog != null) {
- fragment_transaction.remove(previous_new_provider_dialog);
- }
-
- DialogFragment newFragment = NewProviderDialog.newInstance();
- Bundle data = new Bundle();
- data.putString(Provider.MAIN_URL, main_url);
- data.putBoolean(ProviderItem.DANGER_ON, danger_on);
- newFragment.setArguments(data);
- newFragment.show(fragment_transaction, NewProviderDialog.TAG);
- }
-
- /**
- * Once selected a provider, this fragment offers the user to log in,
- * use it anonymously (if possible)
- * or cancel his/her election pressing the back button.
- * @param view
- * @param reason_to_fail
- */
- public void showDownloadFailedDialog(View view, String reason_to_fail) {
- FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction();
- Fragment previous_provider_details_dialog = getFragmentManager().findFragmentByTag(DownloadFailedDialog.TAG);
- if (previous_provider_details_dialog != null) {
- fragment_transaction.remove(previous_provider_details_dialog);
- }
- fragment_transaction.addToBackStack(null);
-
- DialogFragment newFragment = DownloadFailedDialog.newInstance(reason_to_fail);
- newFragment.show(fragment_transaction, DownloadFailedDialog.TAG);
- }
-
- /**
- * Once selected a provider, this fragment offers the user to log in,
- * use it anonymously (if possible)
- * or cancel his/her election pressing the back button.
- * @param view
- */
- public void showProviderDetails(View view) {
- if(setting_up_provider) {
- FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction();
- Fragment previous_provider_details_dialog = getFragmentManager().findFragmentByTag(ProviderDetailFragment.TAG);
- if (previous_provider_details_dialog != null) {
- fragment_transaction.remove(previous_provider_details_dialog);
- }
- fragment_transaction.addToBackStack(null);
-
- DialogFragment newFragment = ProviderDetailFragment.newInstance();
- newFragment.show(fragment_transaction, ProviderDetailFragment.TAG);
- }
- }
-
- public void showAndSelectProvider(String provider_main_url, boolean danger_on) {
- if(getId(provider_main_url).isEmpty()) - showProvider(provider_main_url, danger_on);
- autoSelectProvider(provider_main_url, danger_on); - }
-
- private void showProvider(final String provider_main_url, final boolean danger_on) {
- String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_");
- ProviderItem added_provider = new ProviderItem(provider_name, provider_main_url);
- provider_list_fragment.addItem(added_provider);
- }
-
- private void autoSelectProvider(String provider_main_url, boolean danger_on) {
- getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putBoolean(ProviderItem.DANGER_ON, danger_on).commit();
- onItemSelected(getId(provider_main_url));
- }
-
- /**
- * Asks ProviderAPI to download a new provider.json file
- * @param provider_name
- * @param provider_main_url
- * @param danger_on tells if HTTPS client should bypass certificate errors
- */
- public void setUpProvider(String provider_main_url, boolean danger_on) {
- Intent provider_API_command = new Intent(this, ProviderAPI.class);
- Bundle parameters = new Bundle();
- parameters.putString(Provider.MAIN_URL, provider_main_url);
- parameters.putBoolean(ProviderItem.DANGER_ON, danger_on);
-
- provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER);
- provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters);
- provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - startService(provider_API_command);
- setting_up_provider = true; - } - - public void retrySetUpProvider() { - cancelSettingUpProvider(); - if(!ProviderAPI.caCertDownloaded()) { - addAndSelectNewProvider(ProviderAPI.lastProviderMainUrl(), ProviderAPI.lastDangerOn()); - } else { - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - startService(provider_API_command); - } - } - @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.configuration_wizard_activity, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item){
- switch (item.getItemId()){
- case R.id.about_leap: - startActivityForResult(new Intent(this, AboutActivity.class), 0); - return true; - case R.id.new_provider:
- addAndSelectNewProvider();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- public void showAllProviders() {
- provider_list_fragment = (ProviderListFragment) getFragmentManager().findFragmentByTag(ProviderListFragment.TAG);
- if(provider_list_fragment != null)
- provider_list_fragment.unhideAll();
- }
-
- public void cancelSettingUpProvider() {
- provider_list_fragment = (ProviderListFragment) getFragmentManager().findFragmentByTag(ProviderListFragment.TAG);
- if(provider_list_fragment != null && preferences.contains(ProviderItem.DANGER_ON)) {
- provider_list_fragment.removeLastItem();
- }
- preferences.edit().remove(Provider.KEY).remove(ProviderItem.DANGER_ON).remove(EIP.ALLOWED_ANON).remove(EIP.KEY).commit();
- }
-
- @Override
- public void login() {
- Intent ask_login = new Intent();
- ask_login.putExtra(LogInDialog.VERB, LogInDialog.VERB);
- setResult(RESULT_OK, ask_login);
- setting_up_provider = false;
- finish();
- }
-
- @Override
- public void use_anonymously() {
- setResult(RESULT_OK);
- setting_up_provider = false;
- finish();
- }
-
- public class ProviderAPIBroadcastReceiver_Update extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- int update = intent.getIntExtra(ProviderAPI.CURRENT_PROGRESS, 0);
- mProgressBar.setProgress(update);
- }
- }
-}
diff --git a/src/se/leap/bitmaskclient/Dashboard.java b/src/se/leap/bitmaskclient/Dashboard.java deleted file mode 100644 index b388b84a..00000000 --- a/src/se/leap/bitmaskclient/Dashboard.java +++ /dev/null @@ -1,479 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - package se.leap.bitmaskclient; - -import org.json.JSONException; -import org.json.JSONObject; - -import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.DialogFragment; -import android.app.Fragment; -import android.app.FragmentManager; -import android.app.FragmentTransaction; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.os.Handler; -import android.os.ResultReceiver; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ProgressBar; -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 <meanderingcode@aetherislands.net> - * @author parmegv - */ -public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface,Receiver { - - protected static final int CONFIGURE_LEAP = 0; - protected static final int SWITCH_PROVIDER = 1; - - final public static String SHARED_PREFERENCES = "LEAPPreferences"; - final public static String ACTION_QUIT = "quit"; - public static final String REQUEST_CODE = "request_code"; - - private ProgressBar mProgressBar; - private TextView eipStatus; - private static Context app; - private static SharedPreferences preferences; - private static Provider provider; - - private TextView providerNameTV; - - private boolean authed_eip = false; - - public ProviderAPIResultReceiver providerAPI_result_receiver; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - app = this; - - PRNGFixes.apply(); - // mProgressBar = (ProgressBar) findViewById(R.id.progressbar_dashboard); - // mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - // eipStatus = (TextView) findViewById(R.id.eipStatus); - - mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - - preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); - - authed_eip = preferences.getBoolean(EIP.AUTHED_EIP, false); - if (preferences.getString(Provider.KEY, "").isEmpty()) - startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); - else - buildDashboard(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data){ - if ( requestCode == CONFIGURE_LEAP || requestCode == SWITCH_PROVIDER) { - // It should be equivalent: if ( (requestCode == CONFIGURE_LEAP) || (data!= null && data.hasExtra(STOP_FIRST))) { - if ( resultCode == RESULT_OK ){ - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putInt(EIP.PARSED_SERIAL, 0).commit(); - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); - Intent updateEIP = new Intent(getApplicationContext(), EIP.class); - updateEIP.setAction(EIP.ACTION_UPDATE_EIP_SERVICE); - startService(updateEIP); - buildDashboard(); - invalidateOptionsMenu(); - if(data != null && data.hasExtra(LogInDialog.VERB)) { - View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); - logInDialog(view, Bundle.EMPTY); - } - } else if(resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) { - finish(); - } else - configErrorDialog(); - } - } - - /** - * Dialog shown when encountering a configuration error. Such errors require - * reconfiguring LEAP or aborting the application. - */ - private void configErrorDialog() { - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext()); - alertBuilder.setTitle(getResources().getString(R.string.setup_error_title)); - alertBuilder - .setMessage(getResources().getString(R.string.setup_error_text)) - .setCancelable(false) - .setPositiveButton(getResources().getString(R.string.setup_error_configure_button), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - startActivityForResult(new Intent(getAppContext(),ConfigurationWizard.class),CONFIGURE_LEAP); - } - }) - .setNegativeButton(getResources().getString(R.string.setup_error_close_button), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - SharedPreferences.Editor prefsEdit = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE).edit(); - prefsEdit.remove(Provider.KEY).commit(); - finish(); - } - }) - .show(); - } - - /** - * Inflates permanent UI elements of the View and contains logic for what - * service dependent UI elements to include. - */ - private void buildDashboard() { - provider = Provider.getInstance(); - provider.init( this ); - - setContentView(R.layout.client_dashboard); - - providerNameTV = (TextView) findViewById(R.id.providerName); - providerNameTV.setText(provider.getDomain()); - providerNameTV.setTextSize(28); - - mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - - FragmentManager fragMan = getFragmentManager(); - if ( provider.hasEIP()){ - EipServiceFragment eipFragment = new EipServiceFragment(); - fragMan.beginTransaction().replace(R.id.servicesCollection, eipFragment, EipServiceFragment.TAG).commit(); - } - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - JSONObject provider_json; - try { - provider_json = new JSONObject(getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, "")); - JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); - - if(service_description.getBoolean(Provider.ALLOW_REGISTRATION)) { - if(authed_eip) { - menu.findItem(R.id.login_button).setVisible(false); - menu.findItem(R.id.logout_button).setVisible(true); - } else { - menu.findItem(R.id.login_button).setVisible(true); - menu.findItem(R.id.logout_button).setVisible(false); - } - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return true; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.client_dashboard, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item){ - Intent intent; - switch (item.getItemId()){ - case R.id.about_leap: - intent = new Intent(this, AboutActivity.class); - startActivity(intent); - return true; - case R.id.switch_provider: - if (Provider.getInstance().hasEIP()){ - if (getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getBoolean(EIP.AUTHED_EIP, false)){ - logOut(); - } - eipStop(); - } - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().remove(Provider.KEY).commit(); - startActivityForResult(new Intent(this,ConfigurationWizard.class), SWITCH_PROVIDER); - return true; - case R.id.login_button: - View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); - logInDialog(view, Bundle.EMPTY); - return true; - case R.id.logout_button: - logOut(); - return true; - default: - return super.onOptionsItemSelected(item); - } - - } - - @Override - public void authenticate(String username, String password) { - mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - eipStatus = (TextView) findViewById(R.id.eipStatus); - - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle parameters = new Bundle(); - parameters.putString(LogInDialog.USERNAME, username); - parameters.putString(LogInDialog.PASSWORD, password); - - JSONObject provider_json; - try { - provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - parameters.putString(Provider.API_URL, provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - provider_API_command.setAction(ProviderAPI.SRP_AUTH); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - mProgressBar.setVisibility(ProgressBar.VISIBLE); - eipStatus.setText(R.string.authenticating_message); - //mProgressBar.setMax(4); - startService(provider_API_command); - } - - public void cancelAuthedEipOn() { - EipServiceFragment eipFragment = (EipServiceFragment) getFragmentManager().findFragmentByTag(EipServiceFragment.TAG); - eipFragment.checkEipSwitch(false); - } - - /** - * Asks ProviderAPI to log out. - */ - public void logOut() { - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle parameters = new Bundle(); - - JSONObject provider_json; - try { - provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - parameters.putString(Provider.API_URL, provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - provider_API_command.setAction(ProviderAPI.LOG_OUT); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - if(mProgressBar == null) mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - mProgressBar.setVisibility(ProgressBar.VISIBLE); - if(eipStatus == null) eipStatus = (TextView) findViewById(R.id.eipStatus); - eipStatus.setText(R.string.logout_message); - // eipStatus.setText("Starting to logout"); - - startService(provider_API_command); - //mProgressBar.setMax(1); - - } - - /** - * Shows the log in dialog. - * @param view from which the dialog is created. - */ - public void logInDialog(View view, Bundle resultData) { - FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(LogInDialog.TAG); - if (previous_log_in_dialog != null) { - fragment_transaction.remove(previous_log_in_dialog); - } - fragment_transaction.addToBackStack(null); - - DialogFragment newFragment = LogInDialog.newInstance(); - if(resultData != null && !resultData.isEmpty()) { - newFragment.setArguments(resultData); - } - newFragment.show(fragment_transaction, LogInDialog.TAG); - } - - /** - * Asks ProviderAPI to download an authenticated OpenVPN certificate. - * @param session_id cookie for the server to allow us to download the certificate. - */ - private void downloadAuthedUserCertificate(/*Cookie session_id*/) { - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle parameters = new Bundle(); - parameters.putString(ConfigurationWizard.TYPE_OF_CERTIFICATE, ConfigurationWizard.AUTHED_CERTIFICATE); - /*parameters.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id.getName()); - parameters.putString(ConfigHelper.SESSION_ID_KEY, session_id.getValue());*/ - - provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - startService(provider_API_command); - } - - @Override - public void onReceiveResult(int resultCode, Bundle resultData) { - if(resultCode == ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL){ - String session_id_cookie_key = resultData.getString(ProviderAPI.SESSION_ID_COOKIE_KEY); - String session_id_string = resultData.getString(ProviderAPI.SESSION_ID_KEY); - setResult(RESULT_OK); - - authed_eip = true; - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); - - invalidateOptionsMenu(); - mProgressBar.setVisibility(ProgressBar.GONE); - changeStatusMessage(resultCode); - - //Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); - downloadAuthedUserCertificate(/*session_id*/); - } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_FAILED) { - logInDialog(getCurrentFocus(), resultData); - } else if(resultCode == ProviderAPI.LOGOUT_SUCCESSFUL) { - authed_eip = false; - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); - mProgressBar.setVisibility(ProgressBar.GONE); - mProgressBar.setProgress(0); - invalidateOptionsMenu(); - setResult(RESULT_OK); - changeStatusMessage(resultCode); - - } else if(resultCode == ProviderAPI.LOGOUT_FAILED) { - setResult(RESULT_CANCELED); - changeStatusMessage(resultCode); - mProgressBar.setVisibility(ProgressBar.GONE); - } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { - setResult(RESULT_OK); - changeStatusMessage(resultCode); - mProgressBar.setVisibility(ProgressBar.GONE); - if(EipServiceFragment.isEipSwitchChecked()) - eipStart(); - } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { - setResult(RESULT_CANCELED); - changeStatusMessage(resultCode); - mProgressBar.setVisibility(ProgressBar.GONE); - } - } - - private void changeStatusMessage(final int previous_result_code) { - // TODO Auto-generated method stub - ResultReceiver eip_status_receiver = new ResultReceiver(new Handler()){ - protected void onReceiveResult(int resultCode, Bundle resultData){ - super.onReceiveResult(resultCode, resultData); - String request = resultData.getString(EIP.REQUEST_TAG); - if (request.equalsIgnoreCase(EIP.ACTION_IS_EIP_RUNNING)){ - if (resultCode == Activity.RESULT_OK){ - - switch(previous_result_code){ - case ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL: eipStatus.setText(R.string.succesful_authentication_message); break; - case ProviderAPI.SRP_AUTHENTICATION_FAILED: eipStatus.setText(R.string.authentication_failed_message); break; - case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.authed_secured_status); break; - case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.incorrectly_downloaded_certificate_message); break; - case ProviderAPI.LOGOUT_SUCCESSFUL: eipStatus.setText(R.string.anonymous_secured_status); break; - case ProviderAPI.LOGOUT_FAILED: eipStatus.setText(R.string.log_out_failed_message); break; - - } - } - else if(resultCode == Activity.RESULT_CANCELED){ - - switch(previous_result_code){ - - case ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL: eipStatus.setText(R.string.succesful_authentication_message); break; - case ProviderAPI.SRP_AUTHENTICATION_FAILED: eipStatus.setText(R.string.authentication_failed_message); break; - case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.future_authed_secured_status); break; - case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.incorrectly_downloaded_certificate_message); break; - case ProviderAPI.LOGOUT_SUCCESSFUL: eipStatus.setText(R.string.future_anonymous_secured_status); break; - case ProviderAPI.LOGOUT_FAILED: eipStatus.setText(R.string.log_out_failed_message); break; - } - } - } - - } - }; - eipIsRunning(eip_status_receiver); - } - - /** - * For retrieving the base application Context in classes that don't extend - * Android's Activity class - * - * @return Application Context as defined by <code>this</code> for Dashboard instance - */ - public static Context getAppContext() { - return app; - } - - - @Override - public void startActivityForResult(Intent intent, int requestCode) { - intent.putExtra(Dashboard.REQUEST_CODE, requestCode); - super.startActivityForResult(intent, requestCode); - } - /** - * Send a command to EIP - * - * @param action A valid String constant from EIP class representing an Intent - * filter for the EIP class - */ - private void eipIsRunning(ResultReceiver eip_receiver){ - // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? - Intent eip_intent = new Intent(this, EIP.class); - eip_intent.setAction(EIP.ACTION_IS_EIP_RUNNING); - eip_intent.putExtra(EIP.RECEIVER_TAG, eip_receiver); - startService(eip_intent); - } - - /** - * Send a command to EIP - * - */ - private void eipStop(){ - // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? - Intent eip_intent = new Intent(this, EIP.class); - eip_intent.setAction(EIP.ACTION_STOP_EIP); - // eip_intent.putExtra(EIP.RECEIVER_TAG, eip_receiver); - startService(eip_intent); - - } - - private void eipStart(){ - Intent eip_intent = new Intent(this, EIP.class); - eip_intent.setAction(EIP.ACTION_START_EIP); - eip_intent.putExtra(EIP.RECEIVER_TAG, EipServiceFragment.getReceiver()); - startService(eip_intent); - - } -} diff --git a/src/se/leap/bitmaskclient/DownloadFailedDialog.java b/src/se/leap/bitmaskclient/DownloadFailedDialog.java deleted file mode 100644 index f78002b0..00000000 --- a/src/se/leap/bitmaskclient/DownloadFailedDialog.java +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -package se.leap.bitmaskclient; - -import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.NewProviderDialog.NewProviderDialogInterface; -import se.leap.bitmaskclient.ProviderListContent.ProviderItem; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.os.Bundle; - -/** - * Implements a dialog to show why a download failed. - * - * @author parmegv - * - */ -public class DownloadFailedDialog extends DialogFragment { - - public static String TAG = "downloaded_failed_dialog"; - private String reason_to_fail; - /** - * @return a new instance of this DialogFragment. - */ - public static DialogFragment newInstance(String reason_to_fail) { - DownloadFailedDialog dialog_fragment = new DownloadFailedDialog(); - dialog_fragment.reason_to_fail = reason_to_fail; - return dialog_fragment; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - - builder.setMessage(reason_to_fail) - .setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dismiss(); - interface_with_ConfigurationWizard.retrySetUpProvider(); - } - }) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - interface_with_ConfigurationWizard.cancelSettingUpProvider(); - dialog.dismiss(); - } - }); - - // Create the AlertDialog object and return it - return builder.create(); - } - - public interface DownloadFailedDialogInterface { - public void retrySetUpProvider(); - public void cancelSettingUpProvider(); - } - - DownloadFailedDialogInterface interface_with_ConfigurationWizard; - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - interface_with_ConfigurationWizard = (DownloadFailedDialogInterface) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() - + " must implement NoticeDialogListener"); - } - } - - @Override - public void onCancel(DialogInterface dialog) { - interface_with_ConfigurationWizard.cancelSettingUpProvider(); - dialog.dismiss(); - } - -} diff --git a/src/se/leap/bitmaskclient/EIP.java b/src/se/leap/bitmaskclient/EIP.java deleted file mode 100644 index e773e3b9..00000000 --- a/src/se/leap/bitmaskclient/EIP.java +++ /dev/null @@ -1,623 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - package se.leap.bitmaskclient; - -import java.util.Calendar; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.TreeMap; -import java.util.Vector; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import se.leap.bitmaskclient.R; -import se.leap.openvpn.ConfigParser; -import se.leap.openvpn.ConfigParser.ConfigParseError; -import se.leap.openvpn.LaunchVPN; -import se.leap.openvpn.OpenVpnManagementThread; -import se.leap.openvpn.OpenVpnService; -import se.leap.openvpn.OpenVpnService.LocalBinder; -import se.leap.openvpn.ProfileManager; -import se.leap.openvpn.VpnProfile; -import android.app.Activity; -import android.app.IntentService; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.drm.DrmStore.Action; -import android.os.Bundle; -import android.os.IBinder; -import android.os.ResultReceiver; -import android.util.Log; - -/** - * EIP is the abstract base class for interacting with and managing the Encrypted - * Internet Proxy connection. Connections are started, stopped, and queried through - * this IntentService. - * Contains logic for parsing eip-service.json from the provider, configuring and selecting - * gateways, and controlling {@link .openvpn.OpenVpnService} connections. - * - * @author Sean Leonard <meanderingcode@aetherislands.net> - */ -public final class EIP extends IntentService { - - public final static String AUTHED_EIP = "authed eip"; - public final static String ACTION_START_EIP = "se.leap.bitmaskclient.START_EIP"; - public final static String ACTION_STOP_EIP = "se.leap.bitmaskclient.STOP_EIP"; - public final static String ACTION_UPDATE_EIP_SERVICE = "se.leap.bitmaskclient.UPDATE_EIP_SERVICE"; - public final static String ACTION_IS_EIP_RUNNING = "se.leap.bitmaskclient.IS_RUNNING"; - public final static String EIP_NOTIFICATION = "EIP_NOTIFICATION"; - public final static String ALLOWED_ANON = "allow_anonymous"; - public final static String CERTIFICATE = "cert"; - public final static String PRIVATE_KEY = "private_key"; - public final static String KEY = "eip"; - public final static String PARSED_SERIAL = "eip_parsed_serial"; - public final static String SERVICE_API_PATH = "config/eip-service.json"; - public final static String RECEIVER_TAG = "receiverTag"; - public final static String REQUEST_TAG = "requestTag"; - public final static String TAG = "se.leap.bitmaskclient.EIP"; - - - private static Context context; - private static ResultReceiver mReceiver; - private static OpenVpnService mVpnService; - private static boolean mBound = false; - // Used to store actions to "resume" onServiceConnection - private static String mPending = null; - - private static int parsedEipSerial; - private static JSONObject eipDefinition = null; - - private static OVPNGateway activeGateway = null; - - public EIP(){ - super("LEAPEIP"); - } - - @Override - public void onCreate() { - super.onCreate(); - - context = getApplicationContext(); - - updateEIPService(); - - this.retreiveVpnService(); - } - - @Override - public void onDestroy() { - unbindService(mVpnServiceConn); - mBound = false; - - super.onDestroy(); - } - - @Override - protected void onHandleIntent(Intent intent) { - String action = intent.getAction(); - mReceiver = intent.getParcelableExtra(RECEIVER_TAG); - - if ( action == ACTION_IS_EIP_RUNNING ) - this.isRunning(); - if ( action == ACTION_UPDATE_EIP_SERVICE ) - this.updateEIPService(); - else if ( action == ACTION_START_EIP ) - this.startEIP(); - else if ( action == ACTION_STOP_EIP ) - this.stopEIP(); - } - - /** - * Sends an Intent to bind OpenVpnService. - * Used when OpenVpnService isn't bound but might be running. - */ - private boolean retreiveVpnService() { - Intent bindIntent = new Intent(this,OpenVpnService.class); - bindIntent.setAction(OpenVpnService.RETRIEVE_SERVICE); - return bindService(bindIntent, mVpnServiceConn, BIND_AUTO_CREATE); - } - - 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; - - } - else if (mPending.equals(ACTION_START_EIP)){ - resultCode = (running) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - } - else if (mPending.equals(ACTION_STOP_EIP)){ - resultCode = (running) ? Activity.RESULT_CANCELED - : Activity.RESULT_OK; - } - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); - mReceiver.send(resultCode, resultData); - - mPending = null; - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mBound = false; - - if (mReceiver != null){ - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, EIP_NOTIFICATION); - mReceiver.send(Activity.RESULT_CANCELED, resultData); - } - } - - - }; - - /** - * Attempts to determine if OpenVpnService has an established VPN connection - * through the bound ServiceConnection. If there is no bound service, this - * method will attempt to bind a running OpenVpnService and send - * <code>Activity.RESULT_CANCELED</code> to the ResultReceiver that made the - * request. - * Note: If the request to bind OpenVpnService is successful, the ResultReceiver - * will be notified in {@link onServiceConnected()} - */ - - private void isRunning() { - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); - int resultCode = Activity.RESULT_CANCELED; - if (mBound) { - resultCode = (mVpnService.isRunning()) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - - if (mReceiver != null){ - mReceiver.send(resultCode, resultData); - } - } else { - mPending = ACTION_IS_EIP_RUNNING; - boolean retrieved_vpn_service = retreiveVpnService(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - boolean running = false; - try { - running = mVpnService.isRunning(); - } catch (NullPointerException e){ - e.printStackTrace(); - } - - if (retrieved_vpn_service && running && mReceiver != null){ - mReceiver.send(Activity.RESULT_OK, resultData); - } - else{ - mReceiver.send(Activity.RESULT_CANCELED, resultData); - } - } - } - - /** - * Initiates an EIP connection by selecting a gateway and preparing and sending an - * Intent to {@link se.leap.openvpn.LaunchVPN} - */ - private void startEIP() { - activeGateway = selectGateway(); - - Intent intent = new Intent(this,LaunchVPN.class); - intent.setAction(Intent.ACTION_MAIN); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(LaunchVPN.EXTRA_KEY, activeGateway.mVpnProfile.getUUID().toString() ); - intent.putExtra(LaunchVPN.EXTRA_NAME, activeGateway.mVpnProfile.getName() ); - intent.putExtra(RECEIVER_TAG, mReceiver); - startActivity(intent); - mPending = ACTION_START_EIP; - } - - /** - * Disconnects the EIP connection gracefully through the bound service or forcefully - * if there is no bound service. Sends a message to the requesting ResultReceiver. - */ - private void stopEIP() { - if (mBound) - mVpnService.onRevoke(); - else - OpenVpnManagementThread.stopOpenVPN(); - - if (mReceiver != null){ - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_STOP_EIP); - mReceiver.send(Activity.RESULT_OK, resultData); - } - } - - /** - * Loads eip-service.json from SharedPreferences and calls {@link updateGateways()} - * to parse gateway definitions. - * TODO Implement API call to refresh eip-service.json from the provider - */ - private void updateEIPService() { - try { - eipDefinition = new JSONObject(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(KEY, "")); - parsedEipSerial = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getInt(PARSED_SERIAL, 0); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - if(parsedEipSerial == 0) { - // Delete all vpn profiles - ProfileManager vpl = ProfileManager.getInstance(context); - VpnProfile[] profiles = (VpnProfile[]) vpl.getProfiles().toArray(new VpnProfile[vpl.getProfiles().size()]); - for (int current_profile = 0; current_profile < profiles.length; current_profile++){ - vpl.removeProfile(context, profiles[current_profile]); - } - } - if (eipDefinition.optInt("serial") > parsedEipSerial) - updateGateways(); - } - - /** - * Choose a gateway to connect to based on timezone from system locale data - * - * @return The gateway to connect to - */ - private OVPNGateway selectGateway() { - // TODO Remove String arg constructor in favor of findGatewayByName(String) - - Calendar cal = Calendar.getInstance(); - int localOffset = cal.get(Calendar.ZONE_OFFSET) / 3600000; - TreeMap<Integer, Set<String>> offsets = new TreeMap<Integer, Set<String>>(); - JSONObject locationsObjects = null; - Iterator<String> locations = null; - try { - locationsObjects = eipDefinition.getJSONObject("locations"); - locations = locationsObjects.keys(); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - while (locations.hasNext()) { - String locationName = locations.next(); - JSONObject location = null; - try { - location = locationsObjects.getJSONObject(locationName); - - // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 - int dist = Math.abs(localOffset - location.optInt("timezone")); - // Farther than 12 timezones and it's shorter around the "back" - if (dist > 12) - dist = 12 - (dist -12); // Well i'll be. Absolute values make equations do funny things. - - Set<String> set = offsets.get(dist); - if (set == null) set = new HashSet<String>(); - set.add(locationName); - offsets.put(dist, set); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - - String closestLocation = offsets.isEmpty() ? "" : offsets.firstEntry().getValue().iterator().next(); - JSONArray gateways = null; - String chosenHost = null; - try { - gateways = eipDefinition.getJSONArray("gateways"); - for (int i = 0; i < gateways.length(); i++) { - JSONObject gw = gateways.getJSONObject(i); - if ( gw.getString("location").equalsIgnoreCase(closestLocation) || closestLocation.isEmpty()){ - chosenHost = gw.getString("host"); - break; - } - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - return new OVPNGateway(chosenHost); - } - - /** - * Walk the list of gateways defined in eip-service.json and parse them into - * OVPNGateway objects. - * TODO Store the OVPNGateways (as Serializable) in SharedPreferences - */ - private void updateGateways(){ - JSONArray gatewaysDefined = null; - - try { - gatewaysDefined = eipDefinition.getJSONArray("gateways"); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - for ( int i=0 ; i < gatewaysDefined.length(); i++ ){ - - JSONObject gw = null; - - try { - gw = gatewaysDefined.getJSONObject(i); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - try { - if ( gw.getJSONObject("capabilities").getJSONArray("transport").toString().contains("openvpn") ){ - new OVPNGateway(gw); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putInt(PARSED_SERIAL, eipDefinition.optInt(Provider.API_RETURN_SERIAL)).commit(); - } - - /** - * 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 <meanderingcode@aetherislands.net> - */ - private class OVPNGateway { - - private String TAG = "OVPNGateway"; - - private String mName; - private VpnProfile mVpnProfile; - private JSONObject mGateway; - private HashMap<String,Vector<Vector<String>>> options = new HashMap<String, Vector<Vector<String>>>(); - - - /** - * Attempts to retrieve a VpnProfile by name and build an OVPNGateway around it. - * FIXME This needs to become a findGatewayByName() method - * - * @param name The hostname of the gateway to inflate - */ - private OVPNGateway(String name){ - mName = name; - - this.loadVpnProfile(); - } - - private void loadVpnProfile() { - ProfileManager vpl = ProfileManager.getInstance(context); - - try { - if ( mName == null ) - mVpnProfile = vpl.getProfiles().iterator().next(); - else - mVpnProfile = vpl.getProfileByName(mName); - } catch (NoSuchElementException e) { - updateEIPService(); - this.loadVpnProfile(); // FIXME catch infinite loops - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json - * and create a VpnProfile belonging to it. - * - * @param gateway The JSON OpenVPN gateway definition to parse - */ - protected OVPNGateway(JSONObject gateway){ - - mGateway = gateway; - - // Currently deletes VpnProfile for host, if there already is one, and builds new - ProfileManager vpl = ProfileManager.getInstance(context); - Collection<VpnProfile> profiles = vpl.getProfiles(); - for (Iterator<VpnProfile> it = profiles.iterator(); it.hasNext(); ){ - VpnProfile p = it.next(); - try { - if ( p.mName.equalsIgnoreCase( gateway.getString("host") ) ){ - it.remove(); - vpl.removeProfile(context, p); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - this.parseOptions(); - this.createVPNProfile(); - - setUniqueProfileName(vpl); - vpl.addProfile(mVpnProfile); - vpl.saveProfile(context, mVpnProfile); - vpl.saveProfileList(context); - } - - /** - * Attempts to create a unique profile name from the hostname of the gateway - * - * @param profileManager - */ - private void setUniqueProfileName(ProfileManager profileManager) { - int i=0; - - String newname; - try { - newname = mGateway.getString("host"); - while(profileManager.getProfileByName(newname)!=null) { - i++; - if(i==1) - newname = getString(R.string.converted_profile); - else - newname = getString(R.string.converted_profile_i,i); - } - - mVpnProfile.mName=newname; - } catch (JSONException e) { - // TODO Auto-generated catch block - Log.v(TAG,"Couldn't read gateway name for profile creation!"); - e.printStackTrace(); - } - } - - /** - * FIXME This method is really the outline of the refactoring needed in se.leap.openvpn.ConfigParser - */ - private void parseOptions(){ - - // FIXME move these to a common API (& version) definition place, like ProviderAPI or ConfigHelper - String common_options = "openvpn_configuration"; - String remote = "ip_address"; - String ports = "ports"; - String protos = "protocols"; - String capabilities = "capabilities"; - String location_key = "location"; - String locations = "locations"; - - Vector<String> arg = new Vector<String>(); - Vector<Vector<String>> args = new Vector<Vector<String>>(); - - try { - JSONObject def = (JSONObject) eipDefinition.get(common_options); - Iterator keys = def.keys(); - Vector<Vector<String>> value = new Vector<Vector<String>>(); - while ( keys.hasNext() ){ - String key = keys.next().toString(); - - arg.add(key); - for ( String word : def.getString(key).split(" ") ) - arg.add(word); - value.add( (Vector<String>) arg.clone() ); - options.put(key, (Vector<Vector<String>>) value.clone()); - value.clear(); - arg.clear(); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - try { - arg.add(remote); - arg.add(mGateway.getString(remote)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - args.add((Vector<String>) arg.clone()); - options.put("remote", (Vector<Vector<String>>) args.clone() ); - arg.clear(); - args.clear(); - - - - try { - - arg.add(location_key); - String locationText = ""; - locationText = eipDefinition.getJSONObject(locations).getJSONObject(mGateway.getString(location_key)).getString("name"); - arg.add(locationText); - - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - args.add((Vector<String>) arg.clone()); - options.put("location", (Vector<Vector<String>>) args.clone() ); - - arg.clear(); - args.clear(); - JSONArray protocolsJSON = null; - arg.add("proto"); - try { - protocolsJSON = mGateway.getJSONObject(capabilities).getJSONArray(protos); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - Vector<String> protocols = new Vector<String>(); - for ( int i=0; i<protocolsJSON.length(); i++ ) - protocols.add(protocolsJSON.optString(i)); - if ( protocols.contains("udp")) - arg.add("udp"); - else if ( protocols.contains("tcp")) - arg.add("tcp"); - args.add((Vector<String>) arg.clone()); - options.put("proto", (Vector<Vector<String>>) args.clone()); - arg.clear(); - args.clear(); - - - String port = null; - arg.add("port"); - try { - port = mGateway.getJSONObject(capabilities).getJSONArray(ports).optString(0); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - arg.add(port); - args.add((Vector<String>) arg.clone()); - options.put("port", (Vector<Vector<String>>) args.clone()); - args.clear(); - arg.clear(); - } - - /** - * Create and attach the VpnProfile to our gateway object - */ - protected void createVPNProfile(){ - try { - ConfigParser cp = new ConfigParser(); - cp.setDefinition(options); - VpnProfile vp = cp.convertProfile(); - mVpnProfile = vp; - Log.v(TAG,"Created VPNProfile"); - } catch (ConfigParseError e) { - // FIXME We didn't get a VpnProfile! Error handling! and log level - Log.v(TAG,"Error createing VPNProfile"); - e.printStackTrace(); - } - } - } - -} diff --git a/src/se/leap/bitmaskclient/EipServiceFragment.java b/src/se/leap/bitmaskclient/EipServiceFragment.java deleted file mode 100644 index b4cb541a..00000000 --- a/src/se/leap/bitmaskclient/EipServiceFragment.java +++ /dev/null @@ -1,306 +0,0 @@ -package se.leap.bitmaskclient; - -import se.leap.bitmaskclient.R; -import se.leap.openvpn.LogWindow; -import se.leap.openvpn.OpenVPN; -import se.leap.openvpn.OpenVPN.StateListener; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Fragment; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.ResultReceiver; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.CompoundButton; -import android.widget.RelativeLayout; -import android.widget.Switch; -import android.widget.TextView; - -public class EipServiceFragment extends Fragment implements StateListener, OnCheckedChangeListener { - - protected static final String IS_EIP_PENDING = "is_eip_pending"; - - private View eipFragment; - private static Switch eipSwitch; - private View eipDetail; - private TextView eipStatus; - - private boolean eipAutoSwitched = true; - - private boolean mEipStartPending = false; - - private boolean set_switch_off = false; - - private static EIPReceiver mEIPReceiver; - - - public static String TAG = "se.leap.bitmask.EipServiceFragment"; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false); - - eipDetail = ((RelativeLayout) eipFragment.findViewById(R.id.eipDetail)); - eipDetail.setVisibility(View.VISIBLE); - - View eipSettings = eipFragment.findViewById(R.id.eipSettings); - eipSettings.setVisibility(View.GONE); // FIXME too! - - if (mEipStartPending) - eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); - - eipStatus = (TextView) eipFragment.findViewById(R.id.eipStatus); - - eipSwitch = (Switch) eipFragment.findViewById(R.id.eipSwitch); - - - eipSwitch.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - eipAutoSwitched = false; - return false; - } - }); - eipSwitch.setOnCheckedChangeListener(this); - - - return eipFragment; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mEIPReceiver = new EIPReceiver(new Handler()); - - if (savedInstanceState != null) - mEipStartPending = savedInstanceState.getBoolean(IS_EIP_PENDING); - } - - @Override - public void onResume() { - super.onResume(); - - OpenVPN.addStateListener(this); - if(set_switch_off) { - eipSwitch.setChecked(false); - set_switch_off = false; - } - } - - protected void setSwitchOff(boolean value) { - set_switch_off = value; - } - - @Override - public void onPause() { - super.onPause(); - - OpenVPN.removeStateListener(this); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putBoolean(IS_EIP_PENDING, mEipStartPending); - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (buttonView.equals(eipSwitch) && !eipAutoSwitched){ - boolean allowed_anon = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).getBoolean(EIP.ALLOWED_ANON, false); - String certificate = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).getString(EIP.CERTIFICATE, ""); - if(allowed_anon || !certificate.isEmpty()) { - if (isChecked){ - mEipStartPending = true; - eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); - ((TextView) eipFragment.findViewById(R.id.eipStatus)).setText(R.string.eip_status_start_pending); - eipCommand(EIP.ACTION_START_EIP); - } else { - if (mEipStartPending){ - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); - alertBuilder.setTitle(getResources().getString(R.string.eip_cancel_connect_title)); - alertBuilder - .setMessage(getResources().getString(R.string.eip_cancel_connect_text)) - .setPositiveButton(getResources().getString(R.string.eip_cancel_connect_cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - eipCommand(EIP.ACTION_STOP_EIP); - mEipStartPending = false; - } - }) - .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); - } - } - } - else { - Dashboard dashboard = (Dashboard)getActivity(); - Bundle waiting_on_login = new Bundle(); - waiting_on_login.putBoolean(IS_EIP_PENDING, true); - dashboard.logInDialog(getActivity().getCurrentFocus(), waiting_on_login); - } - } - else { - if(!eipSwitch.isChecked()) - eipStatus.setText(R.string.state_noprocess); - } - eipAutoSwitched = true; - } - - - - /** - * Send a command to EIP - * - * @param action A valid String constant from EIP class representing an Intent - * filter for the EIP class - */ - private void eipCommand(String action){ - // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? - Intent vpnIntent = new Intent(action); - vpnIntent.putExtra(EIP.RECEIVER_TAG, mEIPReceiver); - getActivity().startService(vpnIntent); - } - - @Override - public void updateState(final String state, final String logmessage, final int localizedResId) { - // Note: "states" are not organized anywhere...collected state strings: - // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT ) - getActivity().runOnUiThread(new Runnable() { - - @Override - public void run() { - if (eipStatus != null) { - boolean switchState = true; - String statusMessage = ""; - String prefix = getString(localizedResId); - if (state.equals("CONNECTED")){ - - statusMessage = getString(R.string.eip_state_connected); - getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); - mEipStartPending = false; - } else if (state.equals("BYTECOUNT")) { - statusMessage = getString(R.string.eip_state_connected); getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); - mEipStartPending = false; - - } else if ( (state.equals("NOPROCESS") && !mEipStartPending ) || state.equals("EXITING") && !mEipStartPending || state.equals("FATAL")) { - statusMessage = getString(R.string.eip_state_not_connected); - getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); - mEipStartPending = false; - switchState = false; - } else if (state.equals("NOPROCESS")){ - statusMessage = logmessage; - } else if (state.equals("ASSIGN_IP")){ //don't show assigning message in eipStatus - statusMessage = (String) eipStatus.getText(); - } - 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 <meanderingcode@aetherislands.net> - */ - protected class EIPReceiver extends ResultReceiver { - - protected EIPReceiver(Handler handler){ - super(handler); - } - - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - super.onReceiveResult(resultCode, resultData); - - String request = resultData.getString(EIP.REQUEST_TAG); - boolean checked = false; - - if (request == EIP.ACTION_IS_EIP_RUNNING) { - switch (resultCode){ - case Activity.RESULT_OK: - checked = true; - break; - case Activity.RESULT_CANCELED: - checked = false; - break; - } - } else if (request == EIP.ACTION_START_EIP) { - switch (resultCode){ - case Activity.RESULT_OK: - checked = true; - break; - case Activity.RESULT_CANCELED: - checked = false; - eipFragment.findViewById(R.id.eipProgress).setVisibility(View.GONE); - break; - } - } else if (request == EIP.ACTION_STOP_EIP) { - switch (resultCode){ - case Activity.RESULT_OK: - checked = false; - break; - case Activity.RESULT_CANCELED: - checked = true; - break; - } - } else if (request == EIP.EIP_NOTIFICATION) { - switch (resultCode){ - case Activity.RESULT_OK: - checked = true; - break; - case Activity.RESULT_CANCELED: - checked = false; - break; - } - } - - eipAutoSwitched = true; - eipSwitch.setChecked(checked); - eipAutoSwitched = false; - } - } - - - public static EIPReceiver getReceiver() { - return mEIPReceiver; - } - - public static boolean isEipSwitchChecked() { - return eipSwitch.isChecked(); - } - - public void checkEipSwitch(boolean checked) { - eipSwitch.setChecked(checked); - onCheckedChanged(eipSwitch, checked); - } -} diff --git a/src/se/leap/bitmaskclient/LeapHttpClient.java b/src/se/leap/bitmaskclient/LeapHttpClient.java deleted file mode 100644 index 885b5105..00000000 --- a/src/se/leap/bitmaskclient/LeapHttpClient.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - package se.leap.bitmaskclient; - -import java.security.KeyStore; - -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.SingleClientConnManager; -import android.content.Context; - -/** - * Implements an HTTP client, enabling LEAP Android app to manage its own runtime keystore or bypass default Android security measures. - * - * @author rafa - * - */ -public class LeapHttpClient extends DefaultHttpClient { - - private static LeapHttpClient client; - - /** - * If the class scope client is null, it creates one and imports, if existing, the main certificate from Shared Preferences. - * @param context - * @return the new client. - */ - public static LeapHttpClient getInstance(String cert_string) { - if(client == null) { - if(cert_string != null) { - ConfigHelper.addTrustedCertificate("provider_ca_certificate", cert_string); - } - } - return client; - } - - @Override - protected ClientConnectionManager createClientConnectionManager() { - SchemeRegistry registry = new SchemeRegistry(); - registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - registry.register(new Scheme("https", newSslSocketFactory(), 443)); - - return new SingleClientConnManager(getParams(), registry); - } - - /** - * Uses keystore from ConfigHelper for the SSLSocketFactory. - * @return - */ - private SSLSocketFactory newSslSocketFactory() { - try { - KeyStore trusted = ConfigHelper.getKeystore(); - SSLSocketFactory sf = new SSLSocketFactory(trusted); - - return sf; - } catch (Exception e) { - throw new AssertionError(e); - } - } -} diff --git a/src/se/leap/bitmaskclient/LeapSRPSession.java b/src/se/leap/bitmaskclient/LeapSRPSession.java deleted file mode 100644 index a317d95e..00000000 --- a/src/se/leap/bitmaskclient/LeapSRPSession.java +++ /dev/null @@ -1,341 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - package se.leap.bitmaskclient; - -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Arrays; - -import org.jboss.security.srp.SRPParameters; - -/** - * Implements all SRP algorithm logic. - * - * It's derived from JBoss implementation, with adjustments to make it work with LEAP platform. - * - * @author parmegv - * - */ -public class LeapSRPSession { - - private static String token = ""; - - final public static String SALT = "salt"; - final public static String M1 = "M1"; - final public static String M2 = "M2"; - final public static String TOKEN = "token"; - final public static String AUTHORIZATION_HEADER= "Authorization"; - - private SRPParameters params; - private String username; - private String password; - private BigInteger N; - private byte[] N_bytes; - private BigInteger g; - private BigInteger x; - private BigInteger v; - private BigInteger a; - private BigInteger A; - private byte[] K; - private SecureRandom pseudoRng; - /** The M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) hash */ - private MessageDigest clientHash; - /** The M2 = H(A | M | K) hash */ - private MessageDigest serverHash; - - private static int A_LEN; - - /** Creates a new SRP server session object from the username, password - verifier, - @param username, the user ID - @param password, the user clear text password - @param params, the SRP parameters for the session - */ - public LeapSRPSession(String username, String password, SRPParameters params) - { - this(username, password, params, null); - } - - /** Creates a new SRP server session object from the username, password - verifier, - @param username, the user ID - @param password, the user clear text password - @param params, the SRP parameters for the session - @param abytes, the random exponent used in the A public key - */ - public LeapSRPSession(String username, String password, SRPParameters params, - byte[] abytes) { - this.params = params; - this.g = new BigInteger(1, params.g); - N_bytes = ConfigHelper.trim(params.N); - this.N = new BigInteger(1, N_bytes); - this.username = username; - this.password = password; - - try { - pseudoRng = SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - if( abytes != null ) { - A_LEN = 8*abytes.length; - /* TODO Why did they put this condition? - if( 8*abytes.length != A_LEN ) - throw new IllegalArgumentException("The abytes param must be " - +(A_LEN/8)+" in length, abytes.length="+abytes.length); - */ - this.a = new BigInteger(abytes); - } - else - A_LEN = 64; - - serverHash = newDigest(); - clientHash = newDigest(); - } - - /** - * Calculates the parameter x of the SRP-6a algorithm. - * @param username - * @param password - * @param salt the salt of the user - * @return x - */ - public byte[] calculatePasswordHash(String username, String password, byte[] salt) - { - //password = password.replaceAll("\\\\", "\\\\\\\\"); - // Calculate x = H(s | H(U | ':' | password)) - MessageDigest x_digest = newDigest(); - // Try to convert the username to a byte[] using ISO-8859-1 - byte[] user = null; - byte[] password_bytes = null; - byte[] colon = {}; - String encoding = "ISO-8859-1"; - try { - user = ConfigHelper.trim(username.getBytes(encoding)); - colon = ConfigHelper.trim(":".getBytes(encoding)); - password_bytes = ConfigHelper.trim(password.getBytes(encoding)); - } - catch(UnsupportedEncodingException e) { - // Use the default platform encoding - user = ConfigHelper.trim(username.getBytes()); - colon = ConfigHelper.trim(":".getBytes()); - password_bytes = ConfigHelper.trim(password.getBytes()); - } - - // Build the hash - x_digest.update(user); - x_digest.update(colon); - x_digest.update(password_bytes); - byte[] h = x_digest.digest(); - - x_digest.reset(); - x_digest.update(salt); - x_digest.update(h); - byte[] x_digest_bytes = x_digest.digest(); - - return x_digest_bytes; - } - - /** - * Calculates the parameter V of the SRP-6a algorithm. - * @param k_string constant k predefined by the SRP server implementation. - * @return the value of V - */ - private BigInteger calculateV(String k_string) { - BigInteger k = new BigInteger(k_string, 16); - BigInteger v = k.multiply(g.modPow(x, N)); // g^x % N - return v; - } - - /** - * Calculates the trimmed xor from two BigInteger numbers - * @param b1 the positive source to build first BigInteger - * @param b2 the positive source to build second BigInteger - * @param length - * @return - */ - public byte[] xor(byte[] b1, byte[] b2) - { - //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa - byte[] xor_digest = new BigInteger(1, b1).xor(new BigInteger(1, b2)).toByteArray(); - return ConfigHelper.trim(xor_digest); - } - - /** - * @returns The exponential residue (parameter A) to be sent to the server. - */ - public byte[] exponential() { - byte[] Abytes = null; - if(A == null) { - /* If the random component of A has not been specified use a random - number */ - if( a == null ) { - BigInteger one = BigInteger.ONE; - do { - a = new BigInteger(A_LEN, pseudoRng); - } while(a.compareTo(one) <= 0); - } - A = g.modPow(a, N); - Abytes = ConfigHelper.trim(A.toByteArray()); - } - return Abytes; - } - - /** - * Calculates the parameter M1, to be sent to the SRP server. - * It also updates hashes of client and server for further calculations in other methods. - * It uses a predefined k. - * @param salt_bytes - * @param Bbytes the parameter received from the server, in bytes - * @return the parameter M1 - * @throws NoSuchAlgorithmException - */ - public byte[] response(byte[] salt_bytes, byte[] Bbytes) throws NoSuchAlgorithmException { - // Calculate x = H(s | H(U | ':' | password)) - byte[] M1 = null; - if(new BigInteger(1, Bbytes).mod(new BigInteger(1, N_bytes)) != BigInteger.ZERO) { - byte[] xb = calculatePasswordHash(username, password, ConfigHelper.trim(salt_bytes)); - this.x = new BigInteger(1, xb); - - // Calculate v = kg^x mod N - String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; - this.v = calculateV(k_string); - - // H(N) - byte[] digest_of_n = newDigest().digest(N_bytes); - - // H(g) - byte[] digest_of_g = newDigest().digest(params.g); - - // clientHash = H(N) xor H(g) - byte[] xor_digest = xor(digest_of_n, digest_of_g); - clientHash.update(xor_digest); - - // clientHash = H(N) xor H(g) | H(U) - byte[] username_digest = newDigest().digest(ConfigHelper.trim(username.getBytes())); - username_digest = ConfigHelper.trim(username_digest); - clientHash.update(username_digest); - - // clientHash = H(N) xor H(g) | H(U) | s - clientHash.update(ConfigHelper.trim(salt_bytes)); - - K = null; - - // clientHash = H(N) xor H(g) | H(U) | A - byte[] Abytes = ConfigHelper.trim(A.toByteArray()); - clientHash.update(Abytes); - - // clientHash = H(N) xor H(g) | H(U) | s | A | B - Bbytes = ConfigHelper.trim(Bbytes); - clientHash.update(Bbytes); - - // Calculate S = (B - kg^x) ^ (a + u * x) % N - BigInteger S = calculateS(Bbytes); - byte[] S_bytes = ConfigHelper.trim(S.toByteArray()); - - // K = SessionHash(S) - String hash_algorithm = params.hashAlgorithm; - MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); - K = ConfigHelper.trim(sessionDigest.digest(S_bytes)); - - // clientHash = H(N) xor H(g) | H(U) | A | B | K - clientHash.update(K); - - M1 = ConfigHelper.trim(clientHash.digest()); - - // serverHash = Astr + M + K - serverHash.update(Abytes); - serverHash.update(M1); - serverHash.update(K); - - } - return M1; - } - - /** - * It calculates the parameter S used by response() to obtain session hash K. - * @param Bbytes the parameter received from the server, in bytes - * @return the parameter S - */ - private BigInteger calculateS(byte[] Bbytes) { - byte[] Abytes = ConfigHelper.trim(A.toByteArray()); - Bbytes = ConfigHelper.trim(Bbytes); - byte[] u_bytes = getU(Abytes, Bbytes); - - BigInteger B = new BigInteger(1, Bbytes); - BigInteger u = new BigInteger(1, u_bytes); - - BigInteger B_minus_v = B.subtract(v); - BigInteger a_ux = a.add(u.multiply(x)); - BigInteger S = B_minus_v.modPow(a_ux, N); - return S; - } - - /** - * It calculates the parameter u used by calculateS to obtain S. - * @param Abytes the exponential residue sent to the server - * @param Bbytes the parameter received from the server, in bytes - * @return - */ - public byte[] getU(byte[] Abytes, byte[] Bbytes) { - MessageDigest u_digest = newDigest(); - u_digest.update(ConfigHelper.trim(Abytes)); - u_digest.update(ConfigHelper.trim(Bbytes)); - byte[] u_digest_bytes = u_digest.digest(); - return ConfigHelper.trim(new BigInteger(1, u_digest_bytes).toByteArray()); - } - - /** - * @param M2 The server's response to the client's challenge - * @returns True if and only if the server's response was correct. - */ - public boolean verify(byte[] M2) - { - // M2 = H(A | M1 | K) - M2 = ConfigHelper.trim(M2); - byte[] myM2 = ConfigHelper.trim(serverHash.digest()); - boolean valid = Arrays.equals(M2, myM2); - return valid; - } - - protected static void setToken(String token) { - LeapSRPSession.token = token; - } - - protected static String getToken() { - return token; - } - - /** - * @return a new SHA-256 digest. - */ - public MessageDigest newDigest() - { - MessageDigest md = null; - try { - md = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - return md; - } -} diff --git a/src/se/leap/bitmaskclient/LogInDialog.java b/src/se/leap/bitmaskclient/LogInDialog.java deleted file mode 100644 index a28c9049..00000000 --- a/src/se/leap/bitmaskclient/LogInDialog.java +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - package se.leap.bitmaskclient; - -import se.leap.bitmaskclient.R; -import android.R.color; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.content.res.ColorStateList; -import android.os.Bundle; -import android.provider.CalendarContract.Colors; -import android.view.LayoutInflater; -import android.view.View; -import android.view.animation.AlphaAnimation; -import android.view.animation.BounceInterpolator; -import android.widget.EditText; -import android.widget.TextView; - -/** - * Implements the log in dialog, currently without progress dialog. - * - * It returns to the previous fragment when finished, and sends username and password to the authenticate method. - * - * It also notifies the user if the password is not valid. - * - * @author parmegv - * - */ -public class LogInDialog extends DialogFragment { - - - final public static String TAG = "logInDialog"; - final public static String VERB = "log in"; - final public static String USERNAME = "username"; - final public static String PASSWORD = "password"; - final public static String USERNAME_MISSING = "username missing"; - final public static String PASSWORD_INVALID_LENGTH = "password_invalid_length"; - - private static boolean is_eip_pending = false; - - public AlertDialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - LayoutInflater inflater = getActivity().getLayoutInflater(); - View log_in_dialog_view = inflater.inflate(R.layout.log_in_dialog, null); - - final TextView user_message = (TextView)log_in_dialog_view.findViewById(R.id.user_message); - if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) { - user_message.setText(getArguments().getString(getResources().getString(R.string.user_message))); - } else { - user_message.setVisibility(View.GONE); - } - - final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); - if(getArguments() != null && getArguments().containsKey(USERNAME)) { - String username = getArguments().getString(USERNAME); - username_field.setText(username); - } - if (getArguments() != null && getArguments().containsKey(USERNAME_MISSING)) { - username_field.setError(getResources().getString(R.string.username_ask)); - } - - final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); - if(!username_field.getText().toString().isEmpty() && password_field.isFocusable()) { - password_field.requestFocus(); - } - if (getArguments() != null && getArguments().containsKey(PASSWORD_INVALID_LENGTH)) { - password_field.setError(getResources().getString(R.string.error_not_valid_password_user_message)); - } - if(getArguments() != null && getArguments().getBoolean(EipServiceFragment.IS_EIP_PENDING, false)) { - is_eip_pending = true; - } - - - builder.setView(log_in_dialog_view) - .setPositiveButton(R.string.login_button, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - String username = username_field.getText().toString(); - String password = password_field.getText().toString(); - dialog.dismiss(); - interface_with_Dashboard.authenticate(username, password); - } - }) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - - return builder.create(); - } - - /** - * Interface used to communicate LogInDialog with Dashboard. - * - * @author parmegv - * - */ - public interface LogInDialogInterface { - /** - * Starts authentication process. - * @param username - * @param password - */ - public void authenticate(String username, String password); - public void cancelAuthedEipOn(); - } - - LogInDialogInterface interface_with_Dashboard; - - /** - * @return a new instance of this DialogFragment. - */ - public static DialogFragment newInstance() { - LogInDialog dialog_fragment = new LogInDialog(); - return dialog_fragment; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - interface_with_Dashboard = (LogInDialogInterface) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() - + " must implement LogInDialogListener"); - } - } - - @Override - public void onCancel(DialogInterface dialog) { - if(is_eip_pending) - interface_with_Dashboard.cancelAuthedEipOn(); - super.onCancel(dialog); - } -} diff --git a/src/se/leap/bitmaskclient/NewProviderDialog.java b/src/se/leap/bitmaskclient/NewProviderDialog.java deleted file mode 100644 index cf09c64b..00000000 --- a/src/se/leap/bitmaskclient/NewProviderDialog.java +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - package se.leap.bitmaskclient; - -import se.leap.bitmaskclient.ProviderListContent.ProviderItem; -import se.leap.bitmaskclient.R; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.Toast; - -/** - * Implements the new custom provider dialog. - * - * @author parmegv - * - */ -public class NewProviderDialog extends DialogFragment { - - final public static String TAG = "newProviderDialog"; - - public interface NewProviderDialogInterface { - public void showAndSelectProvider(String url_provider, boolean danger_on); - } - - NewProviderDialogInterface interface_with_ConfigurationWizard; - - /** - * @return a new instance of this DialogFragment. - */ - public static DialogFragment newInstance() { - NewProviderDialog dialog_fragment = new NewProviderDialog(); - return dialog_fragment; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - interface_with_ConfigurationWizard = (NewProviderDialogInterface) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() - + " must implement NoticeDialogListener"); - } - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - LayoutInflater inflater = getActivity().getLayoutInflater(); - View new_provider_dialog_view = inflater.inflate(R.layout.new_provider_dialog, null); - final EditText url_input_field = (EditText)new_provider_dialog_view.findViewById(R.id.new_provider_url); - if(getArguments() != null && getArguments().containsKey(Provider.MAIN_URL)) { - url_input_field.setText(getArguments().getString(Provider.MAIN_URL)); - } - final CheckBox danger_checkbox = (CheckBox)new_provider_dialog_view.findViewById(R.id.danger_checkbox); - if(getArguments() != null && getArguments().containsKey(ProviderItem.DANGER_ON)) { - danger_checkbox.setActivated(getArguments().getBoolean(ProviderItem.DANGER_ON)); - } - - builder.setView(new_provider_dialog_view) - .setMessage(R.string.introduce_new_provider) - .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - String entered_url = url_input_field.getText().toString().trim(); - if(!entered_url.startsWith("https://")) { - if (entered_url.startsWith("http://")){ - entered_url = entered_url.substring("http://".length()); - } - entered_url = "https://".concat(entered_url); - } - boolean danger_on = danger_checkbox.isChecked(); - if(validURL(entered_url)) { - interface_with_ConfigurationWizard.showAndSelectProvider(entered_url, danger_on); - Toast.makeText(getActivity().getApplicationContext(), R.string.valid_url_entered, Toast.LENGTH_LONG).show(); - } else { - url_input_field.setText(""); - danger_checkbox.setChecked(false); - Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_url_entered, Toast.LENGTH_LONG).show();; - } - } - }) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - // Create the AlertDialog object and return it - return builder.create(); - } - - /** - * Checks if the entered url is valid or not. - * @param entered_url - * @return true if it's not empty nor contains only the protocol. - */ - boolean validURL(String entered_url) { - //return !entered_url.isEmpty() && entered_url.matches("http[s]?://.+") && !entered_url.replaceFirst("http[s]?://", "").isEmpty(); - return android.util.Patterns.WEB_URL.matcher(entered_url).matches(); - } -} diff --git a/src/se/leap/bitmaskclient/PRNGFixes.java b/src/se/leap/bitmaskclient/PRNGFixes.java deleted file mode 100644 index a046f01f..00000000 --- a/src/se/leap/bitmaskclient/PRNGFixes.java +++ /dev/null @@ -1,338 +0,0 @@ -package se.leap.bitmaskclient; - -/* - * This software is provided 'as-is', without any express or implied - * warranty. In no event will Google be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, as long as the origin is not misrepresented. - * - * Source: http://android-developers.blogspot.de/2013/08/some-securerandom-thoughts.html - */ - -import android.os.Build; -import android.os.Process; -import android.util.Log; - -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.security.SecureRandom; -import java.security.SecureRandomSpi; -import java.security.Security; - -/** - * Fixes for the output of the default PRNG having low entropy. - * - * The fixes need to be applied via {@link #apply()} before any use of Java - * Cryptography Architecture primitives. A good place to invoke them is in the - * application's {@code onCreate}. - */ -public final class PRNGFixes { - - private static final int VERSION_CODE_JELLY_BEAN = 16; - private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18; - private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL = - getBuildFingerprintAndDeviceSerial(); - - /** Hidden constructor to prevent instantiation. */ - private PRNGFixes() {} - - /** - * Applies all fixes. - * - * @throws SecurityException if a fix is needed but could not be applied. - */ - public static void apply() { - applyOpenSSLFix(); - installLinuxPRNGSecureRandom(); - } - - /** - * Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the - * fix is not needed. - * - * @throws SecurityException if the fix is needed but could not be applied. - */ - private static void applyOpenSSLFix() throws SecurityException { - if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN) - || (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) { - // No need to apply the fix - return; - } - - try { - // Mix in the device- and invocation-specific seed. - Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto") - .getMethod("RAND_seed", byte[].class) - .invoke(null, generateSeed()); - - // Mix output of Linux PRNG into OpenSSL's PRNG - int bytesRead = (Integer) Class.forName( - "org.apache.harmony.xnet.provider.jsse.NativeCrypto") - .getMethod("RAND_load_file", String.class, long.class) - .invoke(null, "/dev/urandom", 1024); - if (bytesRead != 1024) { - throw new IOException( - "Unexpected number of bytes read from Linux PRNG: " - + bytesRead); - } - } catch (Exception e) { - throw new SecurityException("Failed to seed OpenSSL PRNG", e); - } - } - - /** - * Installs a Linux PRNG-backed {@code SecureRandom} implementation as the - * default. Does nothing if the implementation is already the default or if - * there is not need to install the implementation. - * - * @throws SecurityException if the fix is needed but could not be applied. - */ - private static void installLinuxPRNGSecureRandom() - throws SecurityException { - if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) { - // No need to apply the fix - return; - } - - // Install a Linux PRNG-based SecureRandom implementation as the - // default, if not yet installed. - Provider[] secureRandomProviders = - Security.getProviders("SecureRandom.SHA1PRNG"); - if ((secureRandomProviders == null) - || (secureRandomProviders.length < 1) - || (!LinuxPRNGSecureRandomProvider.class.equals( - secureRandomProviders[0].getClass()))) { - Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1); - } - - // Assert that new SecureRandom() and - // SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed - // by the Linux PRNG-based SecureRandom implementation. - SecureRandom rng1 = new SecureRandom(); - if (!LinuxPRNGSecureRandomProvider.class.equals( - rng1.getProvider().getClass())) { - throw new SecurityException( - "new SecureRandom() backed by wrong Provider: " - + rng1.getProvider().getClass()); - } - - SecureRandom rng2; - try { - rng2 = SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - throw new SecurityException("SHA1PRNG not available", e); - } - if (!LinuxPRNGSecureRandomProvider.class.equals( - rng2.getProvider().getClass())) { - throw new SecurityException( - "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong" - + " Provider: " + rng2.getProvider().getClass()); - } - } - - /** - * {@code Provider} of {@code SecureRandom} engines which pass through - * all requests to the Linux PRNG. - */ - private static class LinuxPRNGSecureRandomProvider extends Provider { - - public LinuxPRNGSecureRandomProvider() { - super("LinuxPRNG", - 1.0, - "A Linux-specific random number provider that uses" - + " /dev/urandom"); - // Although /dev/urandom is not a SHA-1 PRNG, some apps - // explicitly request a SHA1PRNG SecureRandom and we thus need to - // prevent them from getting the default implementation whose output - // may have low entropy. - put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName()); - put("SecureRandom.SHA1PRNG ImplementedIn", "Software"); - } - } - - /** - * {@link SecureRandomSpi} which passes all requests to the Linux PRNG - * ({@code /dev/urandom}). - */ - public static class LinuxPRNGSecureRandom extends SecureRandomSpi { - - /* - * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed - * are passed through to the Linux PRNG (/dev/urandom). Instances of - * this class seed themselves by mixing in the current time, PID, UID, - * build fingerprint, and hardware serial number (where available) into - * Linux PRNG. - * - * Concurrency: Read requests to the underlying Linux PRNG are - * serialized (on sLock) to ensure that multiple threads do not get - * duplicated PRNG output. - */ - - private static final File URANDOM_FILE = new File("/dev/urandom"); - - private static final Object sLock = new Object(); - - /** - * Input stream for reading from Linux PRNG or {@code null} if not yet - * opened. - * - * @GuardedBy("sLock") - */ - private static DataInputStream sUrandomIn; - - /** - * Output stream for writing to Linux PRNG or {@code null} if not yet - * opened. - * - * @GuardedBy("sLock") - */ - private static OutputStream sUrandomOut; - - /** - * Whether this engine instance has been seeded. This is needed because - * each instance needs to seed itself if the client does not explicitly - * seed it. - */ - private boolean mSeeded; - - @Override - protected void engineSetSeed(byte[] bytes) { - try { - OutputStream out; - synchronized (sLock) { - out = getUrandomOutputStream(); - } - out.write(bytes); - out.flush(); - } catch (IOException e) { - // On a small fraction of devices /dev/urandom is not writable. - // Log and ignore. - Log.w(PRNGFixes.class.getSimpleName(), - "Failed to mix seed into " + URANDOM_FILE); - } finally { - mSeeded = true; - } - } - - @Override - protected void engineNextBytes(byte[] bytes) { - if (!mSeeded) { - // Mix in the device- and invocation-specific seed. - engineSetSeed(generateSeed()); - } - - try { - DataInputStream in; - synchronized (sLock) { - in = getUrandomInputStream(); - } - synchronized (in) { - in.readFully(bytes); - } - } catch (IOException e) { - throw new SecurityException( - "Failed to read from " + URANDOM_FILE, e); - } - } - - @Override - protected byte[] engineGenerateSeed(int size) { - byte[] seed = new byte[size]; - engineNextBytes(seed); - return seed; - } - - private DataInputStream getUrandomInputStream() { - synchronized (sLock) { - if (sUrandomIn == null) { - // NOTE: Consider inserting a BufferedInputStream between - // DataInputStream and FileInputStream if you need higher - // PRNG output performance and can live with future PRNG - // output being pulled into this process prematurely. - try { - sUrandomIn = new DataInputStream( - new FileInputStream(URANDOM_FILE)); - } catch (IOException e) { - throw new SecurityException("Failed to open " - + URANDOM_FILE + " for reading", e); - } - } - return sUrandomIn; - } - } - - private OutputStream getUrandomOutputStream() throws IOException { - synchronized (sLock) { - if (sUrandomOut == null) { - sUrandomOut = new FileOutputStream(URANDOM_FILE); - } - return sUrandomOut; - } - } - } - - /** - * Generates a device- and invocation-specific seed to be mixed into the - * Linux PRNG. - */ - private static byte[] generateSeed() { - try { - ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream(); - DataOutputStream seedBufferOut = - new DataOutputStream(seedBuffer); - seedBufferOut.writeLong(System.currentTimeMillis()); - seedBufferOut.writeLong(System.nanoTime()); - seedBufferOut.writeInt(Process.myPid()); - seedBufferOut.writeInt(Process.myUid()); - seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL); - seedBufferOut.close(); - return seedBuffer.toByteArray(); - } catch (IOException e) { - throw new SecurityException("Failed to generate seed", e); - } - } - - /** - * Gets the hardware serial number of this device. - * - * @return serial number or {@code null} if not available. - */ - private static String getDeviceSerialNumber() { - // We're using the Reflection API because Build.SERIAL is only available - // since API Level 9 (Gingerbread, Android 2.3). - try { - return (String) Build.class.getField("SERIAL").get(null); - } catch (Exception ignored) { - return null; - } - } - - private static byte[] getBuildFingerprintAndDeviceSerial() { - StringBuilder result = new StringBuilder(); - String fingerprint = Build.FINGERPRINT; - if (fingerprint != null) { - result.append(fingerprint); - } - String serial = getDeviceSerialNumber(); - if (serial != null) { - result.append(serial); - } - try { - return result.toString().getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 encoding not supported"); - } - } -} diff --git a/src/se/leap/bitmaskclient/Provider.java b/src/se/leap/bitmaskclient/Provider.java deleted file mode 100644 index 216f4261..00000000 --- a/src/se/leap/bitmaskclient/Provider.java +++ /dev/null @@ -1,212 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -package se.leap.bitmaskclient; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.Locale; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import android.content.Context; -import android.app.Activity; -import android.content.SharedPreferences; - -/** - * @author Sean Leonard <meanderingcode@aetherislands.net> - * - */ -public final class Provider implements Serializable { - - private static final long serialVersionUID = 6003835972151761353L; - - private static Provider instance = null; - - // We'll access our preferences here - private static SharedPreferences preferences = null; - // Represents our Provider's provider.json - private static JSONObject definition = null; - - final public static String - API_URL = "api_uri", - API_VERSION = "api_version", - ALLOW_REGISTRATION = "allow_registration", - API_RETURN_SERIAL = "serial", - SERVICE = "service", - KEY = "provider", - CA_CERT = "ca_cert", - NAME = "name", - DESCRIPTION = "description", - DOMAIN = "domain", - MAIN_URL = "main_url", - DOT_JSON_URL = "provider_json_url" - ; - - // Array of what API versions we understand - protected static final String[] API_VERSIONS = {"1"}; // I assume we might encounter arbitrary version "numbers" - // Some API pieces we want to know about - private static final String API_TERM_SERVICES = "services"; - private static final String API_TERM_NAME = "name"; - private static final String API_TERM_DOMAIN = "domain"; - private static final String API_TERM_DEFAULT_LANGUAGE = "default_language"; - protected static final String[] API_EIP_TYPES = {"openvpn"}; - - private static final String PREFS_EIP_NAME = null; - - - - // What, no individual fields?! We're going to gamble on org.json.JSONObject and JSONArray - // Supporting multiple API versions will probably break this paradigm, - // Forcing me to write a real constructor and rewrite getters/setters - // Also will refactor if i'm instantiating the same local variables all the time - - /** - * - */ - private Provider() {} - - protected static Provider getInstance(){ - if(instance==null){ - instance = new Provider(); - } - return instance; - } - - protected void init(Activity activity) { - - // Load our preferences from SharedPreferences - // If there's nothing there, we will end up returning a rather empty object - // to whoever called getInstance() and they can run the First Run Wizard - //preferences = context.getgetPreferences(0); // 0 == MODE_PRIVATE, but we don't extend Android's classes... - - // Load SharedPreferences - preferences = activity.getSharedPreferences(Dashboard.SHARED_PREFERENCES,Context.MODE_PRIVATE); - // Inflate our provider.json data - try { - definition = new JSONObject( preferences.getString(Provider.KEY, "") ); - } catch (JSONException e) { - // TODO: handle exception - - // FIXME!! We want "real" data!! - } - } - - protected String getDomain(){ - String domain = "Null"; - try { - domain = definition.getString(API_TERM_DOMAIN); - } catch (JSONException e) { - domain = "Null"; - e.printStackTrace(); - } - return domain; - } - - protected String getName(){ - // Should we pass the locale in, or query the system here? - String lang = Locale.getDefault().getLanguage(); - String name = "Null"; // Should it actually /be/ null, for error conditions? - try { - name = definition.getJSONObject(API_TERM_NAME).getString(lang); - } catch (JSONException e) { - // TODO: Nesting try/catch blocks? Crazy - // Maybe you should actually handle exception? - try { - name = definition.getJSONObject(API_TERM_NAME).getString( definition.getString(API_TERM_DEFAULT_LANGUAGE) ); - } catch (JSONException e2) { - // TODO: Will you handle the exception already? - } - } - - return name; - } - - protected String getDescription(){ - String lang = Locale.getDefault().getLanguage(); - String desc = null; - try { - desc = definition.getJSONObject("description").getString(lang); - } catch (JSONException e) { - // TODO: handle exception!! - try { - desc = definition.getJSONObject("description").getString( definition.getString("default_language") ); - } catch (JSONException e2) { - // TODO: i can't believe you're doing it again! - } - } - - return desc; - } - - protected boolean hasEIP() { - JSONArray services = null; - try { - services = definition.getJSONArray(API_TERM_SERVICES); // returns ["openvpn"] - } catch (Exception e) { - // TODO: handle exception - } - for (int i=0;i<API_EIP_TYPES.length+1;i++){ - try { - // Walk the EIP types array looking for matches in provider's service definitions - if ( Arrays.asList(API_EIP_TYPES).contains( services.getString(i) ) ) - return true; - } catch (NullPointerException e){ - e.printStackTrace(); - return false; - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } - } - return false; - } - - 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() ) - return "OpenVPN"; - else - return null; - } - - 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 - if ( instance.hasEIP() ){ - // TODO Might need an EIP class, but we've only got OpenVPN type right now, - // and only one gateway for our only provider... - // TODO We'll try to load from preferences, have to call ProviderAPI if we've got nothin... - JSONObject eipObject = null; - try { - eipObject = new JSONObject( preferences.getString(PREFS_EIP_NAME, "") ); - } catch (JSONException e) { - // TODO ConfigHelper.rescueJSON() - // Still nothing? - // TODO ProviderAPI.getEIP() - e.printStackTrace(); - } - - return eipObject; - } else - return null; - } -} diff --git a/src/se/leap/bitmaskclient/ProviderAPI.java b/src/se/leap/bitmaskclient/ProviderAPI.java deleted file mode 100644 index 75ef511d..00000000 --- a/src/se/leap/bitmaskclient/ProviderAPI.java +++ /dev/null @@ -1,875 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - package se.leap.bitmaskclient; - -import java.io.DataOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; -import java.net.CookieHandler; -import java.net.CookieManager; -import java.net.CookiePolicy; -import java.net.MalformedURLException; -import java.net.SocketTimeoutException; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLEncoder; -import java.net.UnknownHostException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Scanner; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import org.apache.http.client.ClientProtocolException; -import org.jboss.security.srp.SRPParameters; -import org.json.JSONException; -import org.json.JSONObject; - -import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.ProviderListContent.ProviderItem; -import android.app.IntentService; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.ResultReceiver; -import android.util.Base64; -import android.util.Log; - - -/** - * Implements HTTP api methods used to manage communications with the provider server. - * - * It's an IntentService because it downloads data from the Internet, so it operates in the background. - * - * @author parmegv - * @author MeanderingCode - * - */ -public class ProviderAPI extends IntentService { - - private Handler mHandler; - - final public static String - SET_UP_PROVIDER = "setUpProvider", - DOWNLOAD_NEW_PROVIDER_DOTJSON = "downloadNewProviderDotJSON", - SRP_REGISTER = "srpRegister", - SRP_AUTH = "srpAuth", - LOG_OUT = "logOut", - DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", - PARAMETERS = "parameters", - RESULT_KEY = "result", - RECEIVER_KEY = "receiver", - SESSION_ID_COOKIE_KEY = "session_id_cookie_key", - SESSION_ID_KEY = "session_id", - ERRORS = "errors", - UPDATE_PROGRESSBAR = "update_progressbar", - CURRENT_PROGRESS = "current_progress", - TAG = "provider_api_tag" - ; - - final public static int - CUSTOM_PROVIDER_ADDED = 0, - SRP_AUTHENTICATION_SUCCESSFUL = 3, - SRP_AUTHENTICATION_FAILED = 4, - SRP_REGISTRATION_SUCCESSFUL = 5, - SRP_REGISTRATION_FAILED = 6, - LOGOUT_SUCCESSFUL = 7, - LOGOUT_FAILED = 8, - CORRECTLY_DOWNLOADED_CERTIFICATE = 9, - INCORRECTLY_DOWNLOADED_CERTIFICATE = 10, - PROVIDER_OK = 11, - PROVIDER_NOK = 12, - CORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 13, - INCORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 14 - ; - - private static boolean - CA_CERT_DOWNLOADED = false, - PROVIDER_JSON_DOWNLOADED = false, - EIP_SERVICE_JSON_DOWNLOADED = false - ; - - private static String last_provider_main_url; - private static boolean last_danger_on = false; - private static boolean setting_up_provider = true; - - public static void stop() { - setting_up_provider = false; - } - - public ProviderAPI() { - super("ProviderAPI"); - Log.v("ClassName", "Provider API"); - } - - @Override - public void onCreate() { - super.onCreate(); - mHandler = new Handler(); - CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER) ); - } - - public static String lastProviderMainUrl() { - return last_provider_main_url; - } - - public static boolean lastDangerOn() { - return last_danger_on; - } - - private String formatErrorMessage(final int toast_string_id) { - return "{ \"" + ERRORS + "\" : \""+getResources().getString(toast_string_id)+"\" }"; - } - - @Override - protected void onHandleIntent(Intent command) { - final ResultReceiver receiver = command.getParcelableExtra(RECEIVER_KEY); - String action = command.getAction(); - Bundle parameters = command.getBundleExtra(PARAMETERS); - setting_up_provider = true; - - if(action.equalsIgnoreCase(SET_UP_PROVIDER)) { - Bundle result = setUpProvider(parameters); - if(setting_up_provider) { - if(result.getBoolean(RESULT_KEY)) { - receiver.send(PROVIDER_OK, result); - } else { - receiver.send(PROVIDER_NOK, result); - } - } - } else if (action.equalsIgnoreCase(SRP_AUTH)) { - Bundle session_id_bundle = authenticateBySRP(parameters); - if(session_id_bundle.getBoolean(RESULT_KEY)) { - receiver.send(SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); - } else { - receiver.send(SRP_AUTHENTICATION_FAILED, session_id_bundle); - } - } else if (action.equalsIgnoreCase(LOG_OUT)) { - if(logOut(parameters)) { - receiver.send(LOGOUT_SUCCESSFUL, Bundle.EMPTY); - } else { - receiver.send(LOGOUT_FAILED, Bundle.EMPTY); - } - } else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) { - if(getNewCert(parameters)) { - receiver.send(CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); - } else { - receiver.send(INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); - } - } - } - - /** - * Starts the authentication process using SRP protocol. - * - * @param task containing: username, password and api url. - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if authentication was successful. - */ - private Bundle authenticateBySRP(Bundle task) { - Bundle session_id_bundle = new Bundle(); - int progress = 0; - - String username = (String) task.get(LogInDialog.USERNAME); - String password = (String) task.get(LogInDialog.PASSWORD); - if(validUserLoginData(username, password)) { - - String authentication_server = (String) task.get(Provider.API_URL); - - SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), ConfigHelper.G.toByteArray(), BigInteger.ZERO.toByteArray(), "SHA-256"); - LeapSRPSession client = new LeapSRPSession(username, password, params); - byte[] A = client.exponential(); - broadcast_progress(progress++); - try { - JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); - if(saltAndB.length() > 0) { - String salt = saltAndB.getString(LeapSRPSession.SALT); - broadcast_progress(progress++); - byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); - byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); - if(M1 != null) { - broadcast_progress(progress++); - JSONObject session_idAndM2 = sendM1ToSRPServer(authentication_server, username, M1); - if(session_idAndM2.has(LeapSRPSession.M2) && client.verify((byte[])session_idAndM2.get(LeapSRPSession.M2))) { - session_id_bundle.putBoolean(RESULT_KEY, true); - broadcast_progress(progress++); - } else { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - } - } else { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(LogInDialog.USERNAME, username); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_srp_math_error_user_message)); - } - broadcast_progress(progress++); - } else { - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - session_id_bundle.putBoolean(RESULT_KEY, false); - } - } catch (ClientProtocolException e) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_client_http_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - } catch (IOException e) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_io_exception_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - } catch (JSONException e) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_json_exception_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - } catch (NoSuchAlgorithmException e) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_no_such_algorithm_exception_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - } catch (KeyManagementException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else { - if(!wellFormedPassword(password)) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(LogInDialog.USERNAME, username); - session_id_bundle.putBoolean(LogInDialog.PASSWORD_INVALID_LENGTH, true); - } - if(username.isEmpty()) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putBoolean(LogInDialog.USERNAME_MISSING, true); - } - } - - return session_id_bundle; - } - - /** - * Sets up an intent with the progress value passed as a parameter - * and sends it as a broadcast. - * @param progress - */ - private void broadcast_progress(int progress) { - Intent intentUpdate = new Intent(); - intentUpdate.setAction(UPDATE_PROGRESSBAR); - intentUpdate.addCategory(Intent.CATEGORY_DEFAULT); - intentUpdate.putExtra(CURRENT_PROGRESS, progress); - sendBroadcast(intentUpdate); - } - - /** - * Validates parameters entered by the user to log in - * @param entered_username - * @param entered_password - * @return true if both parameters are present and the entered password length is greater or equal to eight (8). - */ - private boolean validUserLoginData(String entered_username, String entered_password) { - return !(entered_username.isEmpty()) && wellFormedPassword(entered_password); - } - - /** - * Validates a password - * @param entered_password - * @return true if the entered password length is greater or equal to eight (8). - */ - private boolean wellFormedPassword(String entered_password) { - return entered_password.length() >= 8; - } - - /** - * Sends an HTTP POST request to the authentication server with the SRP Parameter A. - * @param server_url - * @param username - * @param clientA First SRP parameter sent - * @return response from authentication server - * @throws ClientProtocolException - * @throws IOException - * @throws JSONException - * @throws CertificateException - * @throws NoSuchAlgorithmException - * @throws KeyStoreException - * @throws KeyManagementException - */ - private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("login", username); - parameters.put("A", clientA); - return sendToServer(server_url + "/sessions.json", "POST", parameters); - - /*HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + "login=" + username + "&&" + "A=" + clientA); - return sendToServer(post);*/ - } - - /** - * Sends an HTTP PUT request to the authentication server with the SRP Parameter M1 (or simply M). - * @param server_url - * @param username - * @param m1 Second SRP parameter sent - * @return response from authentication server - * @throws ClientProtocolException - * @throws IOException - * @throws JSONException - * @throws CertificateException - * @throws NoSuchAlgorithmException - * @throws KeyStoreException - * @throws KeyManagementException - */ - private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { - Map<String, String> parameters = new HashMap<String, String>(); - parameters.put("client_auth", new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); - - //HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + "client_auth" + "=" + new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); - JSONObject json_response = sendToServer(server_url + "/sessions/" + username +".json", "PUT", parameters); - - JSONObject session_idAndM2 = new JSONObject(); - if(json_response.length() > 0) { - byte[] M2_not_trimmed = new BigInteger(json_response.getString(LeapSRPSession.M2), 16).toByteArray(); - /*Cookie session_id_cookie = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies().get(0); - session_idAndM2.put(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id_cookie.getName()); - session_idAndM2.put(ConfigHelper.SESSION_ID_KEY, session_id_cookie.getValue());*/ - session_idAndM2.put(LeapSRPSession.M2, ConfigHelper.trim(M2_not_trimmed)); - CookieHandler.setDefault(null); // we don't need cookies anymore - String token = json_response.getString(LeapSRPSession.TOKEN); - LeapSRPSession.setToken(token); - } - return session_idAndM2; - } - - /** - * Executes an HTTP request expecting a JSON response. - * @param url - * @param request_method - * @param parameters - * @return response from authentication server - * @throws IOException - * @throws JSONException - * @throws MalformedURLException - * @throws CertificateException - * @throws NoSuchAlgorithmException - * @throws KeyStoreException - * @throws KeyManagementException - */ - private JSONObject sendToServer(String url, String request_method, Map<String, String> parameters) throws JSONException, MalformedURLException, IOException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { - JSONObject json_response; - InputStream is = null; - HttpsURLConnection urlConnection = (HttpsURLConnection)new URL(url).openConnection(); - urlConnection.setRequestMethod(request_method); - urlConnection.setChunkedStreamingMode(0); - urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); - try { - - DataOutputStream writer = new DataOutputStream(urlConnection.getOutputStream()); - writer.writeBytes(formatHttpParameters(parameters)); - writer.close(); - - is = urlConnection.getInputStream(); - String plain_response = new Scanner(is).useDelimiter("\\A").next(); - json_response = new JSONObject(plain_response); - } finally { - InputStream error_stream = urlConnection.getErrorStream(); - if(error_stream != null) { - String error_response = new Scanner(error_stream).useDelimiter("\\A").next(); - urlConnection.disconnect(); - Log.d("Error", error_response); - json_response = new JSONObject(error_response); - if(!json_response.isNull(ERRORS) || json_response.has(ERRORS)) { - return new JSONObject(); - } - } - } - - return json_response; - } - - private String formatHttpParameters(Map<String, String> parameters) throws UnsupportedEncodingException { - StringBuilder result = new StringBuilder(); - boolean first = true; - - Iterator<String> parameter_iterator = parameters.keySet().iterator(); - while(parameter_iterator.hasNext()) { - if(first) - first = false; - else - result.append("&&"); - - String key = parameter_iterator.next(); - String value = parameters.get(key); - - result.append(URLEncoder.encode(key, "UTF-8")); - result.append("="); - result.append(URLEncoder.encode(value, "UTF-8")); - } - - return result.toString(); - } - - - - - /** - * Downloads a provider.json from a given URL, adding a new provider using the given name. - * @param task containing a boolean meaning if the provider is custom or not, another boolean meaning if the user completely trusts this provider, the provider name and its provider.json url. - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the update was successful. - */ - private Bundle setUpProvider(Bundle task) { - int progress = 0; - Bundle current_download = new Bundle(); - - if(task != null && task.containsKey(ProviderItem.DANGER_ON) && task.containsKey(Provider.MAIN_URL)) { - last_danger_on = task.getBoolean(ProviderItem.DANGER_ON); - last_provider_main_url = task.getString(Provider.MAIN_URL); - CA_CERT_DOWNLOADED = PROVIDER_JSON_DOWNLOADED = EIP_SERVICE_JSON_DOWNLOADED = false; - } - - if(!CA_CERT_DOWNLOADED) - current_download = downloadCACert(last_provider_main_url, last_danger_on); - if(CA_CERT_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) { - broadcast_progress(progress++); - CA_CERT_DOWNLOADED = true; - if(!PROVIDER_JSON_DOWNLOADED) - current_download = getAndSetProviderJson(last_provider_main_url); - if(PROVIDER_JSON_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) { - broadcast_progress(progress++); - PROVIDER_JSON_DOWNLOADED = true; - current_download = getAndSetEipServiceJson(); - if(current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY)) { - broadcast_progress(progress++); - EIP_SERVICE_JSON_DOWNLOADED = true; - } - } - } - - return current_download; - } - - private Bundle downloadCACert(String provider_main_url, boolean danger_on) { - Bundle result = new Bundle(); - String cert_string = downloadWithCommercialCA(provider_main_url + "/ca.crt", danger_on); - - if(validCertificate(cert_string) && setting_up_provider) { - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putString(Provider.CA_CERT, cert_string).commit(); - result.putBoolean(RESULT_KEY, true); - } else { - String reason_to_fail = pickErrorMessage(cert_string); - result.putString(ERRORS, reason_to_fail); - result.putBoolean(RESULT_KEY, false); - } - - return result; - } - - - public static boolean caCertDownloaded() { - return CA_CERT_DOWNLOADED; - } - - private boolean validCertificate(String cert_string) { - boolean result = false; - if(!ConfigHelper.checkErroneousDownload(cert_string)) { - X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(cert_string); - try { - Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); - result = true; - } catch (CertificateEncodingException e) { - Log.d(TAG, e.getLocalizedMessage()); - } - } - - return result; - } - - private Bundle getAndSetProviderJson(String provider_main_url) { - Bundle result = new Bundle(); - - if(setting_up_provider) { - String provider_dot_json_string = downloadWithProviderCA(provider_main_url + "/provider.json", true); - - try { - JSONObject provider_json = new JSONObject(provider_dot_json_string); - String name = provider_json.getString(Provider.NAME); - //TODO setProviderName(name); - - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putString(Provider.KEY, provider_json.toString()).commit(); - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putBoolean(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)).commit(); - - result.putBoolean(RESULT_KEY, true); - } catch (JSONException e) { - //TODO Error message should be contained in that provider_dot_json_string - String reason_to_fail = pickErrorMessage(provider_dot_json_string); - result.putString(ERRORS, reason_to_fail); - result.putBoolean(RESULT_KEY, false); - } - } - return result; - } - - - - public static boolean providerJsonDownloaded() { - return PROVIDER_JSON_DOWNLOADED; - } - - private Bundle getAndSetEipServiceJson() { - Bundle result = new Bundle(); - String eip_service_json_string = ""; - if(setting_up_provider) { - try { - JSONObject provider_json = new JSONObject(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, "")); - String eip_service_url = provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; - eip_service_json_string = downloadWithProviderCA(eip_service_url, true); - JSONObject eip_service_json = new JSONObject(eip_service_json_string); - eip_service_json.getInt(Provider.API_RETURN_SERIAL); - - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putString(EIP.KEY, eip_service_json.toString()).commit(); - - result.putBoolean(RESULT_KEY, true); - } catch (JSONException e) { - String reason_to_fail = pickErrorMessage(eip_service_json_string); - result.putString(ERRORS, reason_to_fail); - result.putBoolean(RESULT_KEY, false); - } - } - return result; - } - - public static boolean eipServiceDownloaded() { - return EIP_SERVICE_JSON_DOWNLOADED; - } - - /** - * Interprets the error message as a JSON object and extract the "errors" keyword pair. - * If the error message is not a JSON object, then it is returned untouched. - * @param string_json_error_message - * @return final error message - */ - private String pickErrorMessage(String string_json_error_message) { - String error_message = ""; - try { - JSONObject json_error_message = new JSONObject(string_json_error_message); - error_message = json_error_message.getString(ERRORS); - } catch (JSONException e) { - // TODO Auto-generated catch block - error_message = string_json_error_message; - } - - return error_message; - } - - /** - * Tries to download the contents of the provided url using commercially validated CA certificate from chosen provider. - * - * If danger_on flag is true, SSL exceptions will be managed by futher methods that will try to use some bypass methods. - * @param string_url - * @param danger_on if the user completely trusts this provider - * @return - */ - private String downloadWithCommercialCA(String string_url, boolean danger_on) { - - String json_file_content = ""; - - URL provider_url = null; - int seconds_of_timeout = 1; - try { - provider_url = new URL(string_url); - URLConnection url_connection = provider_url.openConnection(); - url_connection.setConnectTimeout(seconds_of_timeout*1000); - if(!LeapSRPSession.getToken().isEmpty()) - url_connection.addRequestProperty(LeapSRPSession.AUTHORIZATION_HEADER, "Token token = " + LeapSRPSession.getToken()); - json_file_content = new Scanner(url_connection.getInputStream()).useDelimiter("\\A").next(); - } catch (MalformedURLException e) { - json_file_content = formatErrorMessage(R.string.malformed_url); - } catch(SocketTimeoutException e) { - json_file_content = formatErrorMessage(R.string.server_unreachable_message); - } catch (IOException e) { - if(provider_url != null) { - json_file_content = downloadWithProviderCA(string_url, danger_on); - } else { - json_file_content = formatErrorMessage(R.string.certificate_error); - } - } catch (Exception e) { - if(provider_url != null && danger_on) { - json_file_content = downloadWithProviderCA(string_url, danger_on); - } - } - - return json_file_content; - } - - /** - * Tries to download the contents of the provided url using not commercially validated CA certificate from chosen provider. - * @param url as a string - * @param danger_on true to download CA certificate in case it has not been downloaded. - * @return an empty string if it fails, the url content if not. - */ - private String downloadWithProviderCA(String url_string, boolean danger_on) { - String json_file_content = ""; - - try { - URL url = new URL(url_string); - // Tell the URLConnection to use a SocketFactory from our SSLContext - HttpsURLConnection urlConnection = - (HttpsURLConnection)url.openConnection(); - urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); - if(!LeapSRPSession.getToken().isEmpty()) - urlConnection.addRequestProperty(LeapSRPSession.AUTHORIZATION_HEADER, "Token token=" + LeapSRPSession.getToken()); - json_file_content = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (UnknownHostException e) { - json_file_content = formatErrorMessage(R.string.server_unreachable_message); - } catch (IOException e) { - // The downloaded certificate doesn't validate our https connection. - if(danger_on) { - json_file_content = downloadWithoutCA(url_string); - } else { - json_file_content = formatErrorMessage(R.string.certificate_error); - } - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyManagementException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return json_file_content; - } - - private javax.net.ssl.SSLSocketFactory getProviderSSLSocketFactory() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException { - String provider_cert_string = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.CA_CERT,""); - - java.security.cert.Certificate provider_certificate = ConfigHelper.parseX509CertificateFromString(provider_cert_string); - - // Create a KeyStore containing our trusted CAs - String keyStoreType = KeyStore.getDefaultType(); - KeyStore keyStore = KeyStore.getInstance(keyStoreType); - keyStore.load(null, null); - keyStore.setCertificateEntry("provider_ca_certificate", provider_certificate); - - // Create a TrustManager that trusts the CAs in our KeyStore - String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); - tmf.init(keyStore); - - // Create an SSLContext that uses our TrustManager - SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, tmf.getTrustManagers(), null); - - return context.getSocketFactory(); - } - - /** - * Downloads the string that's in the url with any certificate. - */ - private String downloadWithoutCA(String url_string) { - String string = ""; - try { - - HostnameVerifier hostnameVerifier = new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }; - - class DefaultTrustManager implements X509TrustManager { - - @Override - public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} - - @Override - public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} - - @Override - public X509Certificate[] getAcceptedIssuers() { - return null; - } - } - - SSLContext context = SSLContext.getInstance("TLS"); - context.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom()); - - URL url = new URL(url_string); - HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection(); - urlConnection.setSSLSocketFactory(context.getSocketFactory()); - urlConnection.setHostnameVerifier(hostnameVerifier); - string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); - System.out.println("String ignoring certificate = " + string); - } catch (FileNotFoundException e) { - e.printStackTrace(); - string = formatErrorMessage(R.string.server_unreachable_message); - } catch (IOException e) { - // The downloaded certificate doesn't validate our https connection. - e.printStackTrace(); - string = formatErrorMessage(R.string.certificate_error); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyManagementException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return string; - } - - /** - * Logs out from the api url retrieved from the task. - * @param task containing api url from which the user will log out - * @return true if there were no exceptions - */ - private boolean logOut(Bundle task) { - try { - String delete_url = task.getString(Provider.API_URL) + "/logout"; - int progress = 0; - - HttpsURLConnection urlConnection = (HttpsURLConnection)new URL(delete_url).openConnection(); - urlConnection.setRequestMethod("DELETE"); - urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); - - int responseCode = urlConnection.getResponseCode(); - broadcast_progress(progress++); - LeapSRPSession.setToken(""); - Log.d(TAG, Integer.toString(responseCode)); - } catch (ClientProtocolException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (IndexOutOfBoundsException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (KeyManagementException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return true; - } - - /** - * Downloads a new OpenVPN certificate, attaching authenticated cookie for authenticated certificate. - * - * @param task containing the type of the certificate to be downloaded - * @return true if certificate was downloaded correctly, false if provider.json or danger_on flag are not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error. - */ - private boolean getNewCert(Bundle task) { - - try { - String type_of_certificate = task.getString(ConfigurationWizard.TYPE_OF_CERTIFICATE); - JSONObject provider_json = new JSONObject(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, "")); - - String provider_main_url = provider_json.getString(Provider.API_URL); - URL new_cert_string_url = new URL(provider_main_url + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.CERTIFICATE); - - boolean danger_on = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getBoolean(ProviderItem.DANGER_ON, false); - - String cert_string = downloadWithProviderCA(new_cert_string_url.toString(), danger_on); - - if(!cert_string.isEmpty()) { - if(ConfigHelper.checkErroneousDownload(cert_string)) { - String reason_to_fail = provider_json.getString(ERRORS); - //result.putString(ConfigHelper.ERRORS_KEY, reason_to_fail); - //result.putBoolean(ConfigHelper.RESULT_KEY, false); - return false; - } else { - - // API returns concatenated cert & key. Split them for OpenVPN options - String certificateString = null, keyString = null; - String[] certAndKey = cert_string.split("(?<=-\n)"); - for (int i=0; i < certAndKey.length-1; i++){ - if ( certAndKey[i].contains("KEY") ) { - keyString = certAndKey[i++] + certAndKey[i]; - } - else if ( certAndKey[i].contains("CERTIFICATE") ) { - certificateString = certAndKey[i++] + certAndKey[i]; - } - } - try { - RSAPrivateKey keyCert = ConfigHelper.parseRsaKeyFromString(keyString); - keyString = Base64.encodeToString( keyCert.getEncoded(), Base64.DEFAULT ); - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putString(EIP.PRIVATE_KEY, "-----BEGIN RSA PRIVATE KEY-----\n"+keyString+"-----END RSA PRIVATE KEY-----").commit(); - - X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(certificateString); - certificateString = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putString(EIP.CERTIFICATE, "-----BEGIN CERTIFICATE-----\n"+certificateString+"-----END CERTIFICATE-----").commit(); - - return true; - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } - } - } else { - return false; - } - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } /*catch (URISyntaxException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - }*/ - } -} diff --git a/src/se/leap/bitmaskclient/ProviderAPIResultReceiver.java b/src/se/leap/bitmaskclient/ProviderAPIResultReceiver.java deleted file mode 100644 index 7b256124..00000000 --- a/src/se/leap/bitmaskclient/ProviderAPIResultReceiver.java +++ /dev/null @@ -1,56 +0,0 @@ -/**
- * Copyright (c) 2013 LEAP Encryption Access Project and contributers
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package se.leap.bitmaskclient;
-
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ResultReceiver;
-
-/**
- * Implements the ResultReceiver needed by Activities using ProviderAPI to receive the results of its operations.
- * @author parmegv
- *
- */
-public class ProviderAPIResultReceiver extends ResultReceiver {
- private Receiver mReceiver;
-
- public ProviderAPIResultReceiver(Handler handler) {
- super(handler);
- // TODO Auto-generated constructor stub
- }
-
- public void setReceiver(Receiver receiver) {
- mReceiver = receiver;
- }
-
- /**
- * Interface to enable ProviderAPIResultReceiver to receive results from the ProviderAPI IntentService.
- * @author parmegv
- *
- */
- public interface Receiver {
- public void onReceiveResult(int resultCode, Bundle resultData);
- }
-
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (mReceiver != null) {
- mReceiver.onReceiveResult(resultCode, resultData);
- }
- }
-
-}
diff --git a/src/se/leap/bitmaskclient/ProviderDetailFragment.java b/src/se/leap/bitmaskclient/ProviderDetailFragment.java deleted file mode 100644 index c067ce2b..00000000 --- a/src/se/leap/bitmaskclient/ProviderDetailFragment.java +++ /dev/null @@ -1,115 +0,0 @@ -package se.leap.bitmaskclient;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.TextView;
-
-public class ProviderDetailFragment extends DialogFragment {
-
- final public static String TAG = "providerDetailFragment";
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- try {
-
- LayoutInflater inflater = getActivity().getLayoutInflater();
- View provider_detail_view = inflater.inflate(R.layout.provider_detail_fragment, null);
-
- JSONObject provider_json = new JSONObject(getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, getActivity().MODE_PRIVATE).getString(Provider.KEY, ""));
-
- final TextView domain = (TextView)provider_detail_view.findViewById(R.id.provider_detail_domain);
- domain.setText(provider_json.getString(Provider.DOMAIN));
- final TextView name = (TextView)provider_detail_view.findViewById(R.id.provider_detail_name);
- name.setText(provider_json.getJSONObject(Provider.NAME).getString("en"));
- final TextView description = (TextView)provider_detail_view.findViewById(R.id.provider_detail_description);
- description.setText(provider_json.getJSONObject(Provider.DESCRIPTION).getString("en"));
-
- builder.setView(provider_detail_view);
- builder.setTitle(R.string.provider_details_fragment_title);
-
- if(anon_allowed(provider_json)) {
- builder.setPositiveButton(R.string.use_anonymously_button, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- interface_with_configuration_wizard.use_anonymously();
- }
- });
- }
-
- if(registration_allowed(provider_json)) {
- builder.setNegativeButton(R.string.login_button, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- interface_with_configuration_wizard.login();
- }
- });
- }
-
- return builder.create();
- } catch (JSONException e) {
- return null;
- }
- }
-
- private boolean anon_allowed(JSONObject provider_json) {
- try {
- JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
- return service_description.has(EIP.ALLOWED_ANON) && service_description.getBoolean(EIP.ALLOWED_ANON);
- } catch (JSONException e) {
- return false;
- }
- }
-
- private boolean registration_allowed(JSONObject provider_json) {
- try {
- JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
- return service_description.has(Provider.ALLOW_REGISTRATION) && service_description.getBoolean(Provider.ALLOW_REGISTRATION);
- } catch (JSONException e) {
- return false;
- }
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- super.onCancel(dialog);
- SharedPreferences.Editor editor = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).edit();
- editor.remove(Provider.KEY).remove(ProviderItem.DANGER_ON).remove(EIP.ALLOWED_ANON).remove(EIP.KEY).commit(); - interface_with_configuration_wizard.showAllProviders(); - }
-
- public static DialogFragment newInstance() {
- ProviderDetailFragment provider_detail_fragment = new ProviderDetailFragment();
- return provider_detail_fragment;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- try {
- interface_with_configuration_wizard = (ProviderDetailFragmentInterface) activity;
- } catch (ClassCastException e) {
- throw new ClassCastException(activity.toString()
- + " must implement LogInDialogListener");
- }
- }
-
- public interface ProviderDetailFragmentInterface {
- public void login();
- public void use_anonymously();
- public void showAllProviders();
- }
-
- ProviderDetailFragmentInterface interface_with_configuration_wizard;
-}
diff --git a/src/se/leap/bitmaskclient/ProviderListAdapter.java b/src/se/leap/bitmaskclient/ProviderListAdapter.java deleted file mode 100644 index 43bba085..00000000 --- a/src/se/leap/bitmaskclient/ProviderListAdapter.java +++ /dev/null @@ -1,114 +0,0 @@ -package se.leap.bitmaskclient; - -import java.util.List; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TwoLineListItem; - -public class ProviderListAdapter<T> extends ArrayAdapter<T> { - private static boolean[] hidden = null; - - public void hide(int position) { - hidden[getRealPosition(position)] = true; - notifyDataSetChanged(); - notifyDataSetInvalidated(); - } - - public void unHide(int position) { - hidden[getRealPosition(position)] = false; - notifyDataSetChanged(); - notifyDataSetInvalidated(); - } - - public void unHideAll() { - for (int provider_index = 0; provider_index < hidden.length; provider_index++) - hidden[provider_index] = false; - } - - private int getRealPosition(int position) { - int hElements = getHiddenCountUpTo(position); - int diff = 0; - for(int i=0;i<hElements;i++) { - diff++; - if(hidden[position+diff]) - i--; - } - return (position + diff); - } - private int getHiddenCount() { - int count = 0; - for(int i=0;i<hidden.length;i++) - if(hidden[i]) - count++; - return count; - } - private int getHiddenCountUpTo(int location) { - int count = 0; - for(int i=0;i<=location;i++) { - if(hidden[i]) - count++; - } - return count; - } - - @Override - public int getCount() { - return (hidden.length - getHiddenCount()); - } - - public ProviderListAdapter(Context mContext, int layout, List<T> objects) { - super(mContext, layout, objects); - if(hidden == null) { - hidden = new boolean[objects.size()]; - for (int i = 0; i < objects.size(); i++) - hidden[i] = false; - } - } - - public ProviderListAdapter(Context mContext, int layout, List<T> objects, boolean show_all_providers) { - super(mContext, layout, objects); - if(show_all_providers) { - hidden = new boolean[objects.size()]; - for (int i = 0; i < objects.size(); i++) - hidden[i] = false; - } - } - - @Override - public void add(T item) { - super.add(item); - boolean[] new_hidden = new boolean[hidden.length+1]; - System.arraycopy(hidden, 0, new_hidden, 0, hidden.length); - new_hidden[hidden.length] = false; - hidden = new_hidden; - } - - @Override - public void remove(T item) { - super.remove(item); - boolean[] new_hidden = new boolean[hidden.length-1]; - System.arraycopy(hidden, 0, new_hidden, 0, hidden.length-1); - hidden = new_hidden; - } - - @Override - public View getView(int index, View convertView, ViewGroup parent) { - TwoLineListItem row; - int position = getRealPosition(index); - if (convertView == null) { - LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - row = (TwoLineListItem)inflater.inflate(R.layout.provider_list_item, null); - } else { - row = (TwoLineListItem)convertView; - } - ProviderListContent.ProviderItem data = ProviderListContent.ITEMS.get(position); - row.getText1().setText(data.domain()); - row.getText2().setText(data.name()); - - return row; - } -} diff --git a/src/se/leap/bitmaskclient/ProviderListContent.java b/src/se/leap/bitmaskclient/ProviderListContent.java deleted file mode 100644 index e1ca4f9a..00000000 --- a/src/se/leap/bitmaskclient/ProviderListContent.java +++ /dev/null @@ -1,112 +0,0 @@ -/**
- * Copyright (c) 2013 LEAP Encryption Access Project and contributers
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package se.leap.bitmaskclient;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.net.URL;
-import java.net.MalformedURLException;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Models the provider list shown in the ConfigurationWizard.
- *
- * @author parmegv
- *
- */
-public class ProviderListContent {
-
- public static List<ProviderItem> ITEMS = new ArrayList<ProviderItem>();
-
- public static Map<String, ProviderItem> ITEM_MAP = new HashMap<String, ProviderItem>();
-
- /**
- * 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 void removeItem(ProviderItem item) {
- ITEMS.remove(item);
- ITEM_MAP.remove(item);
- }
-
- /**
- * A provider item.
- */ - public static class ProviderItem {
- final public static String CUSTOM = "custom";
- final public static String DANGER_ON = "danger_on";
- private String provider_main_url;
- private String name; -
- /**
- * @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) {
-
- 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); - provider_main_url = file_contents.getString(Provider.MAIN_URL);
- this.name = name;
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- /**
- * @param name of the provider
- * @param provider_main_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
- */ - public ProviderItem(String name, String provider_main_url) {
- this.name = name;
- this.provider_main_url = provider_main_url; - }
-
- public String name() { return name; }
-
- public String providerMainUrl() { return provider_main_url; }
-
- public String domain() {
- try {
- return new URL(provider_main_url).getHost();
- } catch (MalformedURLException e) {
- return provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("/.*", "");
- }
- }
- }
-}
diff --git a/src/se/leap/bitmaskclient/ProviderListFragment.java b/src/se/leap/bitmaskclient/ProviderListFragment.java deleted file mode 100644 index db414d87..00000000 --- a/src/se/leap/bitmaskclient/ProviderListFragment.java +++ /dev/null @@ -1,234 +0,0 @@ -/**
- * Copyright (c) 2013 LEAP Encryption Access Project and contributers
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package se.leap.bitmaskclient;
-
-import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
-import android.app.Activity;
-import android.app.ListFragment;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ListView;
-
-/**
- * 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}.
- * <p>
- * Activities containing this fragment MUST implement the {@link Callbacks}
- * interface.
- */
-public class ProviderListFragment extends ListFragment {
-
- public static String TAG = "provider_list_fragment";
- public static String SHOW_ALL_PROVIDERS = "show_all_providers";
- public static String TOP_PADDING = "top padding from providerlistfragment";
- private ProviderListAdapter<ProviderItem> content_adapter;
-
- /**
- * The serialization (saved instance state) Bundle key representing the
- * activated item position. Only used on tablets.
- */
- private static final String STATE_ACTIVATED_POSITION = "activated_position";
-
- /**
- * The fragment's current callback object, which is notified of list item
- * clicks.
- */
- private Callbacks mCallbacks = sDummyCallbacks;
-
- /**
- * The current activated item position. Only used on tablets.
- */
- private int mActivatedPosition = ListView.INVALID_POSITION;
-
- /**
- * A callback interface that all activities containing this fragment must
- * implement. This mechanism allows activities to be notified of item
- * selections.
- */
- public interface Callbacks {
- /**
- * Callback for when an item has been selected.
- */
- public void onItemSelected(String id);
- }
-
- /**
- * A dummy implementation of the {@link Callbacks} interface that does
- * nothing. Used only when this fragment is not attached to an activity.
- */
- private static Callbacks sDummyCallbacks = new Callbacks() {
- @Override
- public void onItemSelected(String id) {
- }
- };
-
- /**
- * Mandatory empty constructor for the fragment manager to instantiate the
- * fragment (e.g. upon screen orientation changes).
- */
- public ProviderListFragment() {
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if(getArguments().containsKey(SHOW_ALL_PROVIDERS))
- content_adapter = new ProviderListAdapter<ProviderListContent.ProviderItem>(
- getActivity(),
- R.layout.provider_list_item,
- ProviderListContent.ITEMS, getArguments().getBoolean(SHOW_ALL_PROVIDERS));
- else
- content_adapter = new ProviderListAdapter<ProviderListContent.ProviderItem>(
- getActivity(),
- R.layout.provider_list_item,
- ProviderListContent.ITEMS);
-
-
- setListAdapter(content_adapter);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- return inflater.inflate(R.layout.provider_list_fragment, container, false);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- // Restore the previously serialized activated item position.
- if (savedInstanceState != null
- && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
- setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
- }
- if(getArguments() != null && getArguments().containsKey(TOP_PADDING)) {
- int topPadding = getArguments().getInt(TOP_PADDING);
- View current_view = getView();
- getView().setPadding(current_view.getPaddingLeft(), topPadding, current_view.getPaddingRight(), current_view.getPaddingBottom());
- }
- }
-
- @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).name());
-
- for(int item_position = 0; item_position < listView.getCount(); item_position++) {
- if(item_position != position)
- content_adapter.hide(item_position);
- }
- }
-
- @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);
- }
- }
-
- public void notifyAdapter() {
- content_adapter.notifyDataSetChanged();
- }
- /**
- * 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;
- }
-
- public void removeLastItem() {
- unhideAll();
- content_adapter.remove(content_adapter.getItem(content_adapter.getCount()-1));
- content_adapter.notifyDataSetChanged();
- }
-
- public void addItem(ProviderItem provider) {
- content_adapter.add(provider);
- content_adapter.notifyDataSetChanged();
- }
-
- public void hideAllBut(int position) {
- int real_count = content_adapter.getCount();
- for(int i = 0; i < real_count;)
- if(i != position) {
- content_adapter.hide(i);
- position--;
- real_count--;
- } else {
- i++;
- } - }
-
- public void unhideAll() {
- if(content_adapter != null) {
- content_adapter.unHideAll();
- content_adapter.notifyDataSetChanged();
- }
- }
-
- /**
- * @return a new instance of this ListFragment.
- */
- public static ProviderListFragment newInstance() {
- return new ProviderListFragment();
- }
-}
|