diff options
Diffstat (limited to 'src/se')
33 files changed, 0 insertions, 9111 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();
- }
-}
diff --git a/src/se/leap/openvpn/CIDRIP.java b/src/se/leap/openvpn/CIDRIP.java deleted file mode 100644 index 8c4b6709..00000000 --- a/src/se/leap/openvpn/CIDRIP.java +++ /dev/null @@ -1,58 +0,0 @@ -package se.leap.openvpn; - -class CIDRIP{ - String mIp; - int len; - public CIDRIP(String ip, String mask){ - mIp=ip; - long netmask=getInt(mask); - - // Add 33. bit to ensure the loop terminates - netmask += 1l << 32; - - int lenZeros = 0; - while((netmask & 0x1) == 0) { - lenZeros++; - netmask = netmask >> 1; - } - // Check if rest of netmask is only 1s - if(netmask != (0x1ffffffffl >> lenZeros)) { - // Asume no CIDR, set /32 - len=32; - } else { - len =32 -lenZeros; - } - - } - @Override - public String toString() { - return String.format("%s/%d",mIp,len); - } - - public boolean normalise(){ - long ip=getInt(mIp); - - long newip = ip & (0xffffffffl << (32 -len)); - if (newip != ip){ - mIp = String.format("%d.%d.%d.%d", (newip & 0xff000000) >> 24,(newip & 0xff0000) >> 16, (newip & 0xff00) >> 8 ,newip & 0xff); - return true; - } else { - return false; - } - } - static long getInt(String ipaddr) { - String[] ipt = ipaddr.split("\\."); - long ip=0; - - ip += Long.parseLong(ipt[0])<< 24; - ip += Integer.parseInt(ipt[1])<< 16; - ip += Integer.parseInt(ipt[2])<< 8; - ip += Integer.parseInt(ipt[3]); - - return ip; - } - public long getInt() { - return getInt(mIp); - } - -}
\ No newline at end of file diff --git a/src/se/leap/openvpn/ConfigParser.java b/src/se/leap/openvpn/ConfigParser.java deleted file mode 100644 index df4eae1b..00000000 --- a/src/se/leap/openvpn/ConfigParser.java +++ /dev/null @@ -1,569 +0,0 @@ -package se.leap.openvpn; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.util.HashMap; -import java.util.Locale; -import java.util.Vector; - -//! Openvpn Config FIle Parser, probably not 100% accurate but close enough - -// And rember, this is valid :) -// --<foo> -// bar -// </foo> -public class ConfigParser { - - - private HashMap<String, Vector<Vector<String>>> options = new HashMap<String, Vector<Vector<String>>>(); - public void parseConfig(Reader reader) throws IOException, ConfigParseError { - - - BufferedReader br =new BufferedReader(reader); - - @SuppressWarnings("unused") - int lineno=0; - - while (true){ - String line = br.readLine(); - if(line==null) - break; - lineno++; - Vector<String> args = parseline(line); - if(args.size() ==0) - continue; - - - if(args.get(0).startsWith("--")) - args.set(0, args.get(0).substring(2)); - - checkinlinefile(args,br); - - String optionname = args.get(0); - if(!options.containsKey(optionname)) { - options.put(optionname, new Vector<Vector<String>>()); - } - options.get(optionname).add(args); - } - } - public void setDefinition(HashMap<String,Vector<Vector<String>>> args) { - options = args; - } - - private void checkinlinefile(Vector<String> args, BufferedReader br) throws IOException, ConfigParseError { - String arg0 = args.get(0); - // CHeck for <foo> - if(arg0.startsWith("<") && arg0.endsWith(">")) { - String argname = arg0.substring(1, arg0.length()-1); - String inlinefile = VpnProfile.INLINE_TAG; - - String endtag = String.format("</%s>",argname); - do { - String line = br.readLine(); - if(line==null){ - throw new ConfigParseError(String.format("No endtag </%s> for starttag <%s> found",argname,argname)); - } - if(line.equals(endtag)) - break; - else { - inlinefile+=line; - inlinefile+= "\n"; - } - } while(true); - - args.clear(); - args.add(argname); - args.add(inlinefile); - } - - } - - enum linestate { - initial, - readin_single_quote - , reading_quoted, reading_unquoted, done} - - private boolean space(char c) { - // I really hope nobody is using zero bytes inside his/her config file - // to sperate parameter but here we go: - return Character.isWhitespace(c) || c == '\0'; - - } - - public class ConfigParseError extends Exception { - private static final long serialVersionUID = -60L; - - public ConfigParseError(String msg) { - super(msg); - } - } - - - // adapted openvpn's parse function to java - private Vector<String> parseline(String line) throws ConfigParseError { - Vector<String> parameters = new Vector<String>(); - - if (line.length()==0) - return parameters; - - - linestate state = linestate.initial; - boolean backslash = false; - char out=0; - - int pos=0; - String currentarg=""; - - do { - // Emulate the c parsing ... - char in; - if(pos < line.length()) - in = line.charAt(pos); - else - in = '\0'; - - if (!backslash && in == '\\' && state != linestate.readin_single_quote) - { - backslash = true; - } - else - { - if (state == linestate.initial) - { - if (!space (in)) - { - if (in == ';' || in == '#') /* comment */ - break; - if (!backslash && in == '\"') - state = linestate.reading_quoted; - else if (!backslash && in == '\'') - state = linestate.readin_single_quote; - else - { - out = in; - state = linestate.reading_unquoted; - } - } - } - else if (state == linestate.reading_unquoted) - { - if (!backslash && space (in)) - state = linestate.done; - else - out = in; - } - else if (state == linestate.reading_quoted) - { - if (!backslash && in == '\"') - state = linestate.done; - else - out = in; - } - else if (state == linestate.readin_single_quote) - { - if (in == '\'') - state = linestate.done; - else - out = in; - } - - if (state == linestate.done) - { - /* ASSERT (parm_len > 0); */ - state = linestate.initial; - parameters.add(currentarg); - currentarg = ""; - out =0; - } - - if (backslash && out!=0) - { - if (!(out == '\\' || out == '\"' || space (out))) - { - throw new ConfigParseError("Options warning: Bad backslash ('\\') usage"); - } - } - backslash = false; - } - - /* store parameter character */ - if (out!=0) - { - currentarg+=out; - } - } while (pos++ < line.length()); - - return parameters; - } - - - final String[] unsupportedOptions = { "config", - "connection", - "proto-force", - "remote-random", - "tls-server" - - }; - - // Ignore all scripts - // in most cases these won't work and user who wish to execute scripts will - // figure out themselves - final String[] ignoreOptions = { "tls-client", - "askpass", - "auth-nocache", - "up", - "down", - "route-up", - "ipchange", - "route-up", - "route-pre-down", - "auth-user-pass-verify", - "dhcp-release", - "dhcp-renew", - "dh", - "management-hold", - "management", - "management-query-passwords", - "pause-exit", - "persist-key", - "register-dns", - "route-delay", - "route-gateway", - "route-metric", - "route-method", - "status", - "script-security", - "show-net-up", - "suppress-timestamps", - "tmp-dir", - "tun-ipv6", - "topology", - "win-sys", - }; - - - // This method is far too long - public VpnProfile convertProfile() throws ConfigParseError{ - boolean noauthtypeset=true; - VpnProfile np = new VpnProfile("converted Profile"); - // Pull, client, tls-client - np.clearDefaults(); - - // XXX we are always client - if(/*options.containsKey("client") || options.containsKey("pull")*/ true) { - np.mUsePull=true; - options.remove("pull"); - options.remove("client"); - } - - Vector<String> secret = getOption("secret", 1, 2); - if(secret!=null) - { - np.mAuthenticationType=VpnProfile.TYPE_STATICKEYS; - noauthtypeset=false; - np.mUseTLSAuth=true; - np.mTLSAuthFilename=secret.get(1); - if(secret.size()==3) - np.mTLSAuthDirection=secret.get(2); - - } - - Vector<Vector<String>> routes = getAllOption("route", 1, 4); - if(routes!=null) { - String routeopt = ""; - for(Vector<String> route:routes){ - String netmask = "255.255.255.255"; - if(route.size() >= 3) - netmask = route.get(2); - String net = route.get(1); - try { - CIDRIP cidr = new CIDRIP(net, netmask); - routeopt+=cidr.toString() + " "; - } catch (ArrayIndexOutOfBoundsException aioob) { - throw new ConfigParseError("Could not parse netmask of route " + netmask); - } catch (NumberFormatException ne) { - throw new ConfigParseError("Could not parse netmask of route " + netmask); - } - - } - np.mCustomRoutes=routeopt; - } - - // Also recognize tls-auth [inline] direction ... - Vector<Vector<String>> tlsauthoptions = getAllOption("tls-auth", 1, 2); - if(tlsauthoptions!=null) { - for(Vector<String> tlsauth:tlsauthoptions) { - if(tlsauth!=null) - { - if(!tlsauth.get(1).equals("[inline]")) { - np.mTLSAuthFilename=tlsauth.get(1); - np.mUseTLSAuth=true; - } - if(tlsauth.size()==3) - np.mTLSAuthDirection=tlsauth.get(2); - } - } - } - - Vector<String> direction = getOption("key-direction", 1, 1); - if(direction!=null) - np.mTLSAuthDirection=direction.get(1); - - - if(getAllOption("redirect-gateway", 0, 5) != null) - np.mUseDefaultRoute=true; - - Vector<String> dev =getOption("dev",1,1); - Vector<String> devtype =getOption("dev-type",1,1); - - if( (devtype !=null && devtype.get(1).equals("tun")) || - (dev!=null && dev.get(1).startsWith("tun")) || - (devtype ==null && dev == null) ) { - //everything okay - } else { - throw new ConfigParseError("Sorry. Only tun mode is supported. See the FAQ for more detail"); - } - - - - Vector<String> mode =getOption("mode",1,1); - if (mode != null){ - if(!mode.get(1).equals("p2p")) - throw new ConfigParseError("Invalid mode for --mode specified, need p2p"); - } - - Vector<String> port = getOption("port", 1,1); - if(port!=null){ - np.mServerPort = port.get(1); - } - - Vector<String> proto = getOption("proto", 1,1); - if(proto!=null){ - np.mUseUdp=isUdpProto(proto.get(1));; - } - - // Parse remote config - Vector<String> remote = getOption("remote",1,3); - if(remote != null){ - switch (remote.size()) { - case 4: - np.mUseUdp=isUdpProto(remote.get(3)); - case 3: - np.mServerPort = remote.get(2); - case 2: - np.mServerName = remote.get(1); - } - } - - // Parse remote config - Vector<String> location = getOption("location",0,2); - if(location != null && location.size() == 2){ - np.mLocation = location.get(1).replace("__", ", "); - } - - Vector<Vector<String>> dhcpoptions = getAllOption("dhcp-option", 2, 2); - if(dhcpoptions!=null) { - for(Vector<String> dhcpoption:dhcpoptions) { - String type=dhcpoption.get(1); - String arg = dhcpoption.get(2); - if(type.equals("DOMAIN")) { - np.mSearchDomain=dhcpoption.get(2); - } else if(type.equals("DNS")) { - np.mOverrideDNS=true; - if(np.mDNS1.equals(VpnProfile.DEFAULT_DNS1)) - np.mDNS1=arg; - else - np.mDNS2=arg; - } - } - } - - Vector<String> ifconfig = getOption("ifconfig", 2, 2); - if(ifconfig!=null) { - CIDRIP cidr = new CIDRIP(ifconfig.get(1), ifconfig.get(2)); - np.mIPv4Address=cidr.toString(); - } - - if(getOption("remote-random-hostname", 0, 0)!=null) - np.mUseRandomHostname=true; - - if(getOption("float", 0, 0)!=null) - np.mUseFloat=true; - - if(getOption("comp-lzo", 0, 1)!=null) - np.mUseLzo=true; - - Vector<String> cipher = getOption("cipher", 1, 1); - if(cipher!=null) - np.mCipher= cipher.get(1); - - Vector<String> ca = getOption("ca",1,1); - if(ca!=null){ - np.mCaFilename = ca.get(1); - } - - Vector<String> cert = getOption("cert",1,1); - if(cert!=null){ - np.mClientCertFilename = cert.get(1); - np.mAuthenticationType = VpnProfile.TYPE_CERTIFICATES; - noauthtypeset=false; - } - Vector<String> key= getOption("key",1,1); - if(key!=null) - np.mClientKeyFilename=key.get(1); - - Vector<String> pkcs12 = getOption("pkcs12",1,1); - if(pkcs12!=null) { - np.mPKCS12Filename = pkcs12.get(1); - np.mAuthenticationType = VpnProfile.TYPE_KEYSTORE; - noauthtypeset=false; - } - - Vector<String> tlsremote = getOption("tls-remote",1,1); - if(tlsremote!=null){ - np.mRemoteCN = tlsremote.get(1); - np.mCheckRemoteCN=true; - } - - Vector<String> verb = getOption("verb",1,1); - if(verb!=null){ - np.mVerb=verb.get(1); - } - - - if(getOption("nobind", 0, 0) != null) - np.mNobind=true; - - if(getOption("persist-tun", 0,0) != null) - np.mPersistTun=true; - - Vector<String> connectretry = getOption("connect-retry", 1, 1); - if(connectretry!=null) - np.mConnectRetry =connectretry.get(1); - - Vector<String> connectretrymax = getOption("connect-retry-max", 1, 1); - if(connectretrymax!=null) - np.mConnectRetryMax =connectretrymax.get(1); - - Vector<Vector<String>> remotetls = getAllOption("remote-cert-tls", 1, 1); - if(remotetls!=null) - if(remotetls.get(0).get(1).equals("server")) - np.mExpectTLSCert=true; - else - options.put("remotetls",remotetls); - - Vector<String> authuser = getOption("auth-user-pass",0,1); - if(authuser !=null){ - if(noauthtypeset) { - np.mAuthenticationType=VpnProfile.TYPE_USERPASS; - } else if(np.mAuthenticationType==VpnProfile.TYPE_CERTIFICATES) { - np.mAuthenticationType=VpnProfile.TYPE_USERPASS_CERTIFICATES; - } else if(np.mAuthenticationType==VpnProfile.TYPE_KEYSTORE) { - np.mAuthenticationType=VpnProfile.TYPE_USERPASS_KEYSTORE; - } - if(authuser.size()>1) { - // Set option value to password get to get canche to embed later. - np.mUsername=null; - np.mPassword=authuser.get(1); - useEmbbedUserAuth(np,authuser.get(1)); - } - - } - - - // Check the other options - - checkIgnoreAndInvalidOptions(np); - fixup(np); - - return np; - } - - private boolean isUdpProto(String proto) throws ConfigParseError { - boolean isudp; - if(proto.equals("udp") || proto.equals("udp6")) - isudp=true; - else if (proto.equals("tcp-client") || - proto.equals("tcp") || - proto.equals("tcp6") || - proto.endsWith("tcp6-client")) - isudp =false; - else - throw new ConfigParseError("Unsupported option to --proto " + proto); - return isudp; - } - - static public void useEmbbedUserAuth(VpnProfile np,String inlinedata) - { - String data = inlinedata.replace(VpnProfile.INLINE_TAG, ""); - String[] parts = data.split("\n"); - if(parts.length >= 2) { - np.mUsername=parts[0]; - np.mPassword=parts[1]; - } - } - - private void checkIgnoreAndInvalidOptions(VpnProfile np) throws ConfigParseError { - for(String option:unsupportedOptions) - if(options.containsKey(option)) - throw new ConfigParseError(String.format("Unsupported Option %s encountered in config file. Aborting",option)); - - for(String option:ignoreOptions) - // removing an item which is not in the map is no error - options.remove(option); - - if(options.size()> 0) { - String custom = "# These Options were found in the config file do not map to config settings:\n"; - - for(Vector<Vector<String>> option:options.values()) { - for(Vector<String> optionsline: option) { - for (String arg : optionsline) - custom+= VpnProfile.openVpnEscape(arg) + " "; - } - custom+="\n"; - - } - np.mCustomConfigOptions = custom; - np.mUseCustomConfig=true; - - } - } - - - private void fixup(VpnProfile np) { - if(np.mRemoteCN.equals(np.mServerName)) { - np.mRemoteCN=""; - } - } - - private Vector<String> getOption(String option, int minarg, int maxarg) throws ConfigParseError { - Vector<Vector<String>> alloptions = getAllOption(option, minarg, maxarg); - if(alloptions==null) - return null; - else - return alloptions.lastElement(); - } - - - private Vector<Vector<String>> getAllOption(String option, int minarg, int maxarg) throws ConfigParseError { - Vector<Vector<String>> args = options.get(option); - if(args==null) - return null; - - for(Vector<String> optionline:args) - - if(optionline.size()< (minarg+1) || optionline.size() > maxarg+1) { - String err = String.format(Locale.getDefault(),"Option %s has %d parameters, expected between %d and %d", - option,optionline.size()-1,minarg,maxarg ); - throw new ConfigParseError(err); - } - options.remove(option); - return args; - } - -} - - - - diff --git a/src/se/leap/openvpn/LICENSE.txt b/src/se/leap/openvpn/LICENSE.txt deleted file mode 100644 index d897edea..00000000 --- a/src/se/leap/openvpn/LICENSE.txt +++ /dev/null @@ -1,24 +0,0 @@ -License for OpenVPN for Android. Please note that the thirdparty libraries/executables may have other license (OpenVPN, lzo, OpenSSL, Google Breakpad) - -Copyright (c) 2012-2013, Arne Schwabe - All rights reserved. - -If you need a non GPLv2 license of the source please contact me. - -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 2 -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, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -In addition, as a special exception, the copyright holders give -permission to link the code of portions of this program with the -OpenSSL library. diff --git a/src/se/leap/openvpn/LaunchVPN.java b/src/se/leap/openvpn/LaunchVPN.java deleted file mode 100644 index 89f2d372..00000000 --- a/src/se/leap/openvpn/LaunchVPN.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package se.leap.openvpn; - -import java.io.IOException; -import java.util.Collection; -import java.util.Vector; - -import se.leap.bitmaskclient.ConfigHelper; -import se.leap.bitmaskclient.EIP; -import se.leap.bitmaskclient.R; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ListActivity; -import android.content.ActivityNotFoundException; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.VpnService; -import android.os.Bundle; -import android.os.Parcelable; -import android.os.ResultReceiver; -import android.preference.PreferenceManager; -import android.text.InputType; -import android.text.method.PasswordTransformationMethod; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.ListView; -import android.widget.TextView; - -/** - * This Activity actually handles two stages of a launcher shortcut's life cycle. - * - * 1. Your application offers to provide shortcuts to the launcher. When - * the user installs a shortcut, an activity within your application - * generates the actual shortcut and returns it to the launcher, where it - * is shown to the user as an icon. - * - * 2. Any time the user clicks on an installed shortcut, an intent is sent. - * Typically this would then be handled as necessary by an activity within - * your application. - * - * We handle stage 1 (creating a shortcut) by simply sending back the information (in the form - * of an {@link android.content.Intent} that the launcher will use to create the shortcut. - * - * You can also implement this in an interactive way, by having your activity actually present - * UI for the user to select the specific nature of the shortcut, such as a contact, picture, URL, - * media item, or action. - * - * We handle stage 2 (responding to a shortcut) in this sample by simply displaying the contents - * of the incoming {@link android.content.Intent}. - * - * In a real application, you would probably use the shortcut intent to display specific content - * or start a particular operation. - */ -public class LaunchVPN extends ListActivity implements OnItemClickListener { - - public static final String EXTRA_KEY = "se.leap.openvpn.shortcutProfileUUID"; - public static final String EXTRA_NAME = "se.leap.openvpn.shortcutProfileName"; - public static final String EXTRA_HIDELOG = "se.leap.openvpn.showNoLogWindow";; - - public static final int START_VPN_PROFILE= 70; - - // Dashboard, maybe more, want to know! - private ResultReceiver mReceiver; - - private ProfileManager mPM; - private VpnProfile mSelectedProfile; - private boolean mhideLog=false; - - private boolean mCmfixed=false; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - mPM =ProfileManager.getInstance(this); - - } - - @Override - protected void onStart() { - super.onStart(); - // Resolve the intent - - final Intent intent = getIntent(); - final String action = intent.getAction(); - - // If something wants feedback, they sent us a Receiver - mReceiver = intent.getParcelableExtra(EIP.RECEIVER_TAG); - - // If the intent is a request to create a shortcut, we'll do that and exit - - - if(Intent.ACTION_MAIN.equals(action)) { - // we got called to be the starting point, most likely a shortcut - String shortcutUUID = intent.getStringExtra( EXTRA_KEY); - String shortcutName = intent.getStringExtra( EXTRA_NAME); - mhideLog = intent.getBooleanExtra(EXTRA_HIDELOG, false); - - VpnProfile profileToConnect = ProfileManager.get(shortcutUUID); - if(shortcutName != null && profileToConnect ==null) - profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName); - - if(profileToConnect ==null) { - OpenVPN.logError(R.string.shortcut_profile_notfound); - // show Log window to display error - showLogWindow(); - finish(); - return; - } - - mSelectedProfile = profileToConnect; - launchVPN(); - - } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) { - createListView(); - } - } - - private void createListView() { - ListView lv = getListView(); - //lv.setTextFilterEnabled(true); - - Collection<VpnProfile> vpnlist = mPM.getProfiles(); - - Vector<String> vpnnames=new Vector<String>(); - for (VpnProfile vpnProfile : vpnlist) { - vpnnames.add(vpnProfile.mName); - } - - - - ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,vpnnames); - lv.setAdapter(adapter); - - lv.setOnItemClickListener(this); - } - - /** - * This function creates a shortcut and returns it to the caller. There are actually two - * intents that you will send back. - * - * The first intent serves as a container for the shortcut and is returned to the launcher by - * setResult(). This intent must contain three fields: - * - * <ul> - * <li>{@link android.content.Intent#EXTRA_SHORTCUT_INTENT} The shortcut intent.</li> - * <li>{@link android.content.Intent#EXTRA_SHORTCUT_NAME} The text that will be displayed with - * the shortcut.</li> - * <li>{@link android.content.Intent#EXTRA_SHORTCUT_ICON} The shortcut's icon, if provided as a - * bitmap, <i>or</i> {@link android.content.Intent#EXTRA_SHORTCUT_ICON_RESOURCE} if provided as - * a drawable resource.</li> - * </ul> - * - * If you use a simple drawable resource, note that you must wrapper it using - * {@link android.content.Intent.ShortcutIconResource}, as shown below. This is required so - * that the launcher can access resources that are stored in your application's .apk file. If - * you return a bitmap, such as a thumbnail, you can simply put the bitmap into the extras - * bundle using {@link android.content.Intent#EXTRA_SHORTCUT_ICON}. - * - * The shortcut intent can be any intent that you wish the launcher to send, when the user - * clicks on the shortcut. Typically this will be {@link android.content.Intent#ACTION_VIEW} - * with an appropriate Uri for your content, but any Intent will work here as long as it - * triggers the desired action within your Activity. - * @param profile - */ - private void setupShortcut(VpnProfile profile) { - // First, set up the shortcut intent. For this example, we simply create an intent that - // will bring us directly back to this activity. A more typical implementation would use a - // data Uri in order to display a more specific result, or a custom action in order to - // launch a specific operation. - - Intent shortcutIntent = new Intent(Intent.ACTION_MAIN); - shortcutIntent.setClass(this, LaunchVPN.class); - shortcutIntent.putExtra(EXTRA_KEY,profile.getUUID().toString()); - - // Then, set up the container intent (the response to the caller) - - Intent intent = new Intent(); - intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, profile.getName()); - Parcelable iconResource = Intent.ShortcutIconResource.fromContext( - this, R.drawable.icon); - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); - - // Now, return the result to the launcher - - setResult(RESULT_OK, intent); - } - - - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, - long id) { - String profilename = ((TextView) view).getText().toString(); - - VpnProfile profile = mPM.getProfileByName(profilename); - - // if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) { - setupShortcut(profile); - finish(); - return; - // } - - } - - - - private void askForPW(final int type) { - - final EditText entry = new EditText(this); - entry.setSingleLine(); - entry.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); - entry.setTransformationMethod(new PasswordTransformationMethod()); - - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle("Need " + getString(type)); - dialog.setMessage("Enter the password for profile " + mSelectedProfile.mName); - dialog.setView(entry); - - dialog.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String pw = entry.getText().toString(); - if(type == R.string.password) { - mSelectedProfile.mTransientPW = pw; - } else { - mSelectedProfile.mTransientPCKS12PW = pw; - } - onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null); - - } - - }); - dialog.setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }); - - dialog.create().show(); - - } - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if(requestCode==START_VPN_PROFILE) { - if(resultCode == Activity.RESULT_OK) { - int needpw = mSelectedProfile.needUserPWInput(); - if(needpw !=0) { - askForPW(needpw); - } else { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - boolean showlogwindow = prefs.getBoolean("showlogwindow", false); - - if(!mhideLog && showlogwindow) - showLogWindow(); - new startOpenVpnThread().start(); - } - } else if (resultCode == Activity.RESULT_CANCELED) { - // User does not want us to start, so we just vanish (well, now we tell our receiver, then vanish) - Bundle resultData = new Bundle(); - // For now, nothing else is calling, so this "request" string is good enough - resultData.putString(EIP.REQUEST_TAG, EIP.ACTION_START_EIP); - mReceiver.send(RESULT_CANCELED, resultData); - finish(); - } - } - } - void showLogWindow() { - - Intent startLW = new Intent(getBaseContext(),LogWindow.class); - startLW.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivity(startLW); - - } - - void showConfigErrorDialog(int vpnok) { - AlertDialog.Builder d = new AlertDialog.Builder(this); - d.setTitle(R.string.config_error_found); - d.setMessage(vpnok); - d.setPositiveButton(android.R.string.ok, new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - - } - }); - d.show(); - } - - void launchVPN () { - int vpnok = mSelectedProfile.checkProfile(this); - if(vpnok!= R.string.no_error_found) { - showConfigErrorDialog(vpnok); - return; - } - - Intent intent = VpnService.prepare(this); - // Check if we want to fix /dev/tun - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - boolean usecm9fix = prefs.getBoolean("useCM9Fix", false); - boolean loadTunModule = prefs.getBoolean("loadTunModule", false); - - if(loadTunModule) - execeuteSUcmd("insmod /system/lib/modules/tun.ko"); - - if(usecm9fix && !mCmfixed ) { - execeuteSUcmd("chown system /dev/tun"); - } - - - if (intent != null) { - // Start the query - try { - startActivityForResult(intent, START_VPN_PROFILE); - } catch (ActivityNotFoundException ane) { - // Shame on you Sony! At least one user reported that - // an official Sony Xperia Arc S image triggers this exception - OpenVPN.logError(R.string.no_vpn_support_image); - showLogWindow(); - } - } else { - onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null); - } - - } - - private void execeuteSUcmd(String command) { - ProcessBuilder pb = new ProcessBuilder(new String[] {"su","-c",command}); - try { - Process p = pb.start(); - int ret = p.waitFor(); - if(ret ==0) - mCmfixed=true; - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private class startOpenVpnThread extends Thread { - - @Override - public void run() { - VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext()); - // Tell whom-it-may-concern that we started VPN - Bundle resultData = new Bundle(); - // For now, nothing else is calling, so this "request" string is good enough - resultData.putString(EIP.REQUEST_TAG, EIP.ACTION_START_EIP); - mReceiver.send(RESULT_OK, resultData); - finish(); - - } - - } - - -} diff --git a/src/se/leap/openvpn/LogWindow.java b/src/se/leap/openvpn/LogWindow.java deleted file mode 100644 index b87c4999..00000000 --- a/src/se/leap/openvpn/LogWindow.java +++ /dev/null @@ -1,340 +0,0 @@ -package se.leap.openvpn; - -import java.util.Vector; - -import se.leap.bitmaskclient.R; - -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.app.ListActivity; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.database.DataSetObserver; -import android.os.Bundle; -import android.os.Handler; -import android.os.Handler.Callback; -import android.os.Message; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.Toast; -import se.leap.openvpn.OpenVPN.LogItem; -import se.leap.openvpn.OpenVPN.LogListener; -import se.leap.openvpn.OpenVPN.StateListener; - -public class LogWindow extends ListActivity implements StateListener { - private static final int START_VPN_CONFIG = 0; - private String[] mBconfig=null; - - - class LogWindowListAdapter implements ListAdapter, LogListener, Callback { - - private static final int MESSAGE_NEWLOG = 0; - - private static final int MESSAGE_CLEARLOG = 1; - - private Vector<String> myEntries=new Vector<String>(); - - private Handler mHandler; - - private Vector<DataSetObserver> observers=new Vector<DataSetObserver>(); - - - public LogWindowListAdapter() { - initLogBuffer(); - - if (mHandler == null) { - mHandler = new Handler(this); - } - - OpenVPN.addLogListener(this); - } - - - - private void initLogBuffer() { - myEntries.clear(); - for (LogItem litem : OpenVPN.getlogbuffer()) { - myEntries.add(litem.getString(getContext())); - } - } - - String getLogStr() { - String str = ""; - for(String entry:myEntries) { - str+=entry + '\n'; - } - return str; - } - - - private void shareLog() { - Intent shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.putExtra(Intent.EXTRA_TEXT, getLogStr()); - shareIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.bitmask_openvpn_log_file)); - shareIntent.setType("text/plain"); - startActivity(Intent.createChooser(shareIntent, "Send Logfile")); - } - - @Override - public void registerDataSetObserver(DataSetObserver observer) { - observers.add(observer); - - } - - @Override - public void unregisterDataSetObserver(DataSetObserver observer) { - observers.remove(observer); - } - - @Override - public int getCount() { - return myEntries.size(); - } - - @Override - public Object getItem(int position) { - return myEntries.get(position); - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - TextView v; - if(convertView==null) - v = new TextView(getBaseContext()); - else - v = (TextView) convertView; - v.setText(myEntries.get(position)); - return v; - } - - @Override - public int getItemViewType(int position) { - return 0; - } - - @Override - public int getViewTypeCount() { - return 1; - } - - @Override - public boolean isEmpty() { - return myEntries.isEmpty(); - - } - - @Override - public boolean areAllItemsEnabled() { - return true; - } - - @Override - public boolean isEnabled(int position) { - return true; - } - - @Override - public void newLog(LogItem logmessage) { - Message msg = Message.obtain(); - msg.what=MESSAGE_NEWLOG; - Bundle mbundle=new Bundle(); - mbundle.putString("logmessage", logmessage.getString(getBaseContext())); - msg.setData(mbundle); - mHandler.sendMessage(msg); - } - - @Override - public boolean handleMessage(Message msg) { - // We have been called - if(msg.what==MESSAGE_NEWLOG) { - - String logmessage = msg.getData().getString("logmessage"); - myEntries.add(logmessage); - - for (DataSetObserver observer : observers) { - observer.onChanged(); - } - } else if (msg.what == MESSAGE_CLEARLOG) { - initLogBuffer(); - for (DataSetObserver observer : observers) { - observer.onInvalidated(); - } - } - - return true; - } - - void clearLog() { - // Actually is probably called from GUI Thread as result of the user - // pressing a button. But better safe than sorry - OpenVPN.clearLog(); - OpenVPN.logMessage(0,"","Log cleared."); - mHandler.sendEmptyMessage(MESSAGE_CLEARLOG); - } - } - - - - private LogWindowListAdapter ladapter; - private TextView mSpeedView; - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(item.getItemId()==R.id.clearlog) { - ladapter.clearLog(); - return true; - } else if(item.getItemId()==R.id.cancel){ - Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.title_cancel); - builder.setMessage(R.string.cancel_connection_query); - builder.setNegativeButton(android.R.string.no, null); - builder.setPositiveButton(android.R.string.yes, new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - ProfileManager.setConntectedVpnProfileDisconnected(getApplicationContext()); - OpenVpnManagementThread.stopOpenVPN(); - } - }); - - builder.show(); - return true; - } else if(item.getItemId()==R.id.info) { - if(mBconfig==null) - OpenVPN.triggerLogBuilderConfig(); - - } else if(item.getItemId()==R.id.send) { - ladapter.shareLog(); - } - - return super.onOptionsItemSelected(item); - - } - - protected Context getContext() { - return this; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.logmenu, menu); - return true; - } - - - @Override - protected void onResume() { - super.onResume(); - OpenVPN.addStateListener(this); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == START_VPN_CONFIG && resultCode==RESULT_OK) { - String configuredVPN = data.getStringExtra(VpnProfile.EXTRA_PROFILEUUID); - - final VpnProfile profile = ProfileManager.get(configuredVPN); - ProfileManager.getInstance(this).saveProfile(this, profile); - // Name could be modified, reset List adapter - - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle(R.string.configuration_changed); - dialog.setMessage(R.string.restart_vpn_after_change); - - - dialog.setPositiveButton(R.string.restart, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Intent intent = new Intent(getBaseContext(), LaunchVPN.class); - intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUIDString()); - intent.setAction(Intent.ACTION_MAIN); - startActivity(intent); - } - - - }); - dialog.setNegativeButton(R.string.ignore, null); - dialog.create().show(); - } - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onStop() { - super.onStop(); - OpenVPN.removeStateListener(this); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.logwindow); - ListView lv = getListView(); - - lv.setOnItemLongClickListener(new OnItemLongClickListener() { - - @Override - public boolean onItemLongClick(AdapterView<?> parent, View view, - int position, long id) { - ClipboardManager clipboard = (ClipboardManager) - getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("Log Entry",((TextView) view).getText()); - clipboard.setPrimaryClip(clip); - Toast.makeText(getBaseContext(), R.string.copied_entry, Toast.LENGTH_SHORT).show(); - return true; - } - }); - - ladapter = new LogWindowListAdapter(); - lv.setAdapter(ladapter); - - mSpeedView = (TextView) findViewById(R.id.speed); - } - - @Override - public void updateState(final String status,final String logmessage, final int resid) { - runOnUiThread(new Runnable() { - - @Override - public void run() { - String prefix=getString(resid) + ":"; - if (status.equals("BYTECOUNT") || status.equals("NOPROCESS") ) - prefix=""; - mSpeedView.setText(prefix + logmessage); - } - }); - - } - - @Override - protected void onDestroy() { - super.onDestroy(); - OpenVPN.removeLogListener(ladapter); - } - -} diff --git a/src/se/leap/openvpn/NetworkSateReceiver.java b/src/se/leap/openvpn/NetworkSateReceiver.java deleted file mode 100644 index 777402b4..00000000 --- a/src/se/leap/openvpn/NetworkSateReceiver.java +++ /dev/null @@ -1,86 +0,0 @@ -package se.leap.openvpn;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
-import android.preference.PreferenceManager;
-import se.leap.bitmaskclient.R;
-
-public class NetworkSateReceiver extends BroadcastReceiver {
- private int lastNetwork=-1;
- private OpenVpnManagementThread mManangement;
-
- private String lastStateMsg=null;
-
- public NetworkSateReceiver(OpenVpnManagementThread managementThread) {
- super();
- mManangement = managementThread;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- NetworkInfo networkInfo = getCurrentNetworkInfo(context);
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- boolean sendusr1 = prefs.getBoolean("netchangereconnect", true);
-
- String netstatestring;
- if(networkInfo==null)
- netstatestring = "not connected";
- else {
- String subtype = networkInfo.getSubtypeName();
- if(subtype==null)
- subtype = "";
- String extrainfo = networkInfo.getExtraInfo();
- if(extrainfo==null)
- extrainfo="";
-
- /*
- if(networkInfo.getType()==android.net.ConnectivityManager.TYPE_WIFI) {
- WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- WifiInfo wifiinfo = wifiMgr.getConnectionInfo();
- extrainfo+=wifiinfo.getBSSID();
-
- subtype += wifiinfo.getNetworkId();
- }*/
-
-
-
- netstatestring = String.format("%2$s %4$s to %1$s %3$s",networkInfo.getTypeName(),
- networkInfo.getDetailedState(),extrainfo,subtype );
- }
-
-
-
- if(networkInfo!=null && networkInfo.getState() == State.CONNECTED) {
- int newnet = networkInfo.getType();
-
- if(sendusr1 && lastNetwork!=newnet)
- mManangement.reconnect();
-
- lastNetwork = newnet;
- } else if (networkInfo==null) {
- // Not connected, stop openvpn, set last connected network to no network
- lastNetwork=-1;
- if(sendusr1)
- mManangement.signalusr1();
- }
-
- if(!netstatestring.equals(lastStateMsg))
- OpenVPN.logInfo(R.string.netstatus, netstatestring);
- lastStateMsg=netstatestring;
-
- }
-
- private NetworkInfo getCurrentNetworkInfo(Context context) {
- ConnectivityManager conn = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
-
- NetworkInfo networkInfo = conn.getActiveNetworkInfo();
- return networkInfo;
- }
-
-}
diff --git a/src/se/leap/openvpn/OpenVPN.java b/src/se/leap/openvpn/OpenVPN.java deleted file mode 100644 index 8acdc423..00000000 --- a/src/se/leap/openvpn/OpenVPN.java +++ /dev/null @@ -1,250 +0,0 @@ -package se.leap.openvpn; - -import java.util.LinkedList; -import java.util.Locale; -import java.util.Vector; - -import se.leap.bitmaskclient.R; - - -import android.content.Context; -import android.os.Build; -import android.util.Log; - -public class OpenVPN { - - - public static LinkedList<LogItem> logbuffer; - - private static Vector<LogListener> logListener; - private static Vector<StateListener> stateListener; - private static String[] mBconfig; - - private static String mLaststatemsg; - - private static String mLaststate; - - private static int mLastStateresid=R.string.state_noprocess; - public static String TAG="se.leap.openvpn.OpenVPN"; - - static { - logbuffer = new LinkedList<LogItem>(); - logListener = new Vector<OpenVPN.LogListener>(); - stateListener = new Vector<OpenVPN.StateListener>(); - logInformation(); - } - - public static class LogItem { - public static final int ERROR = 1; - public static final int INFO = 2; - public static final int VERBOSE = 3; - - private Object [] mArgs = null; - private String mMessage = null; - private int mRessourceId; - // Default log priority - int mLevel = INFO; - - public LogItem(int ressourceId, Object[] args) { - mRessourceId = ressourceId; - mArgs = args; - } - - - public LogItem(int loglevel,int ressourceId, Object[] args) { - mRessourceId = ressourceId; - mArgs = args; - mLevel = loglevel; - } - - - public LogItem(String message) { - - mMessage = message; - } - - public LogItem(int loglevel, String msg) { - mLevel = loglevel; - mMessage = msg; - } - - - public LogItem(int loglevel, int ressourceId) { - mRessourceId =ressourceId; - mLevel = loglevel; - } - - - public String getString(Context c) { - if(mMessage !=null) { - return mMessage; - } else { - if(c!=null) { - if(mArgs == null) - return c.getString(mRessourceId); - else - return c.getString(mRessourceId,mArgs); - } else { - String str = String.format(Locale.ENGLISH,"Log (no context) resid %d", mRessourceId); - if(mArgs !=null) - for(Object o:mArgs) - str += "|" + o.toString(); - return str; - } - } - } - } - - private static final int MAXLOGENTRIES = 500; - - - public static final String MANAGMENT_PREFIX = "M:"; - - - - - - - public interface LogListener { - void newLog(LogItem logItem); - } - - public interface StateListener { - void updateState(String state, String logmessage, int localizedResId); - } - - synchronized static void logMessage(int level,String prefix, String message) - { - newlogItem(new LogItem(prefix + message)); - Log.d("OpenVPN log item", message); - } - - synchronized static void clearLog() { - logbuffer.clear(); - logInformation(); - } - - private static void logInformation() { - - logInfo(R.string.mobile_info,Build.MODEL, Build.BOARD,Build.BRAND,Build.VERSION.SDK_INT); - } - - public synchronized static void addLogListener(LogListener ll){ - logListener.add(ll); - } - - public synchronized static void removeLogListener(LogListener ll) { - logListener.remove(ll); - } - - - public synchronized static void addStateListener(StateListener sl){ - stateListener.add(sl); - if(mLaststate!=null) - sl.updateState(mLaststate, mLaststatemsg, mLastStateresid); - } - - private static int getLocalizedState(String state){ - if (state.equals("CONNECTING")) - return R.string.state_connecting; - else if (state.equals("WAIT")) - return R.string.state_wait; - else if (state.equals("AUTH")) - return R.string.state_auth; - else if (state.equals("GET_CONFIG")) - return R.string.state_get_config; - else if (state.equals("ASSIGN_IP")) - return R.string.state_assign_ip; - else if (state.equals("ADD_ROUTES")) - return R.string.state_add_routes; - else if (state.equals("CONNECTED")) - return R.string.state_connected; - else if (state.equals("RECONNECTING")) - return R.string.state_reconnecting; - else if (state.equals("EXITING")) - return R.string.state_exiting; - else if (state.equals("RESOLVE")) - return R.string.state_resolve; - else if (state.equals("TCP_CONNECT")) - return R.string.state_tcp_connect; - else if (state.equals("FATAL")) - return R.string.eip_state_not_connected; - else - return R.string.unknown_state; - - } - - public synchronized static void removeStateListener(StateListener sl) { - stateListener.remove(sl); - } - - - synchronized public static LogItem[] getlogbuffer() { - - // The stoned way of java to return an array from a vector - // brought to you by eclipse auto complete - return (LogItem[]) logbuffer.toArray(new LogItem[logbuffer.size()]); - - } - public static void logBuilderConfig(String[] bconfig) { - mBconfig = bconfig; - } - public static void triggerLogBuilderConfig() { - if(mBconfig==null) { - logMessage(0, "", "No active interface"); - } else { - for (String item : mBconfig) { - logMessage(0, "", item); - } - } - - } - - public static void updateStateString (String state, String msg) { - int rid = getLocalizedState(state); - updateStateString(state, msg,rid); - } - - public synchronized static void updateStateString(String state, String msg, int resid) { - if (! "BYTECOUNT".equals(state)) { - mLaststate= state; - mLaststatemsg = msg; - mLastStateresid = resid; - - for (StateListener sl : stateListener) { - sl.updateState(state,msg,resid); - } - } - } - - public static void logInfo(String message) { - newlogItem(new LogItem(LogItem.INFO, message)); - } - - public static void logInfo(int ressourceId, Object... args) { - newlogItem(new LogItem(LogItem.INFO, ressourceId, args)); - } - - private static void newlogItem(LogItem logItem) { - logbuffer.addLast(logItem); - if(logbuffer.size()>MAXLOGENTRIES) - logbuffer.removeFirst(); - - for (LogListener ll : logListener) { - ll.newLog(logItem); - } - } - - public static void logError(String msg) { - newlogItem(new LogItem(LogItem.ERROR, msg)); - - } - - public static void logError(int ressourceId) { - newlogItem(new LogItem(LogItem.ERROR, ressourceId)); - } - public static void logError(int ressourceId, Object... args) { - newlogItem(new LogItem(LogItem.ERROR, ressourceId,args)); - } - -} diff --git a/src/se/leap/openvpn/OpenVPNThread.java b/src/se/leap/openvpn/OpenVPNThread.java deleted file mode 100644 index ffd21732..00000000 --- a/src/se/leap/openvpn/OpenVPNThread.java +++ /dev/null @@ -1,130 +0,0 @@ -package se.leap.openvpn;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.LinkedList;
-
-import se.leap.bitmaskclient.R;
-
-import android.util.Log;
-import se.leap.openvpn.OpenVPN.LogItem;
-
-public class OpenVPNThread implements Runnable {
- private static final String DUMP_PATH_STRING = "Dump path: ";
- private static final String TAG = "OpenVPN";
- private String[] mArgv;
- private Process mProcess;
- private String mNativeDir;
- private OpenVpnService mService;
- private String mDumpPath;
-
- public OpenVPNThread(OpenVpnService service,String[] argv, String nativelibdir)
- {
- mArgv = argv;
- mNativeDir = nativelibdir;
- mService = service;
- }
-
- public void stopProcess() {
- mProcess.destroy();
- }
-
-
-
- @Override
- public void run() {
- try {
- Log.i(TAG, "Starting openvpn");
- startOpenVPNThreadArgs(mArgv);
- Log.i(TAG, "Giving up");
- } catch (Exception e) {
- e.printStackTrace();
- Log.e(TAG, "OpenVPNThread Got " + e.toString());
- } finally {
- int exitvalue = 0;
- try {
- exitvalue = mProcess.waitFor();
- } catch ( IllegalThreadStateException ite) {
- OpenVPN.logError("Illegal Thread state: " + ite.getLocalizedMessage());
- } catch (InterruptedException ie) {
- OpenVPN.logError("InterruptedException: " + ie.getLocalizedMessage());
- }
- if( exitvalue != 0)
- OpenVPN.logError("Process exited with exit value " + exitvalue);
-
-// OpenVPN.updateStateString("NOPROCESS","No process running.", R.string.state_noprocess); fixes bug #4565
- if(mDumpPath!=null) {
- try {
- BufferedWriter logout = new BufferedWriter(new FileWriter(mDumpPath + ".log"));
- for(LogItem li :OpenVPN.getlogbuffer()){
- logout.write(li.getString(null) + "\n");
- }
- logout.close();
- OpenVPN.logError(R.string.minidump_generated);
- } catch (IOException e) {
- OpenVPN.logError("Writing minidump log: " +e.getLocalizedMessage());
- }
- }
-
- mService.processDied();
- Log.i(TAG, "Exiting");
- }
- }
-
- private void startOpenVPNThreadArgs(String[] argv) {
- LinkedList<String> argvlist = new LinkedList<String>();
-
- for(String arg:argv)
- argvlist.add(arg);
-
- ProcessBuilder pb = new ProcessBuilder(argvlist);
- // Hack O rama
-
- // Hack until I find a good way to get the real library path
- String applibpath = argv[0].replace("/cache/" + VpnProfile.MINIVPN , "/lib");
-
- String lbpath = pb.environment().get("LD_LIBRARY_PATH");
- if(lbpath==null)
- lbpath = applibpath;
- else
- lbpath = lbpath + ":" + applibpath;
-
- if (!applibpath.equals(mNativeDir)) {
- lbpath = lbpath + ":" + mNativeDir;
- }
-
- pb.environment().put("LD_LIBRARY_PATH", lbpath);
- pb.redirectErrorStream(true);
- try {
- mProcess = pb.start();
- // Close the output, since we don't need it
- mProcess.getOutputStream().close();
- InputStream in = mProcess.getInputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(in));
-
- while(true) {
- String logline = br.readLine();
- if(logline==null)
- return;
-
- if (logline.startsWith(DUMP_PATH_STRING))
- mDumpPath = logline.substring(DUMP_PATH_STRING.length());
-
-
- OpenVPN.logMessage(0, "P:", logline);
- }
-
-
- } catch (IOException e) {
- OpenVPN.logMessage(0, "", "Error reading from output of OpenVPN process"+ e.getLocalizedMessage());
- e.printStackTrace();
- stopProcess();
- }
-
-
- }
-}
diff --git a/src/se/leap/openvpn/OpenVpnManagementThread.java b/src/se/leap/openvpn/OpenVpnManagementThread.java deleted file mode 100644 index 27a3db65..00000000 --- a/src/se/leap/openvpn/OpenVpnManagementThread.java +++ /dev/null @@ -1,592 +0,0 @@ -package se.leap.openvpn;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.util.LinkedList;
-import java.util.Vector;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-
-import se.leap.bitmaskclient.R;
-import android.content.SharedPreferences;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.os.Build;
-import android.os.ParcelFileDescriptor;
-import android.preference.PreferenceManager;
-import android.util.Base64;
-import android.util.Log;
-
-public class OpenVpnManagementThread implements Runnable {
-
- private static final String TAG = "openvpn";
- private LocalSocket mSocket;
- private VpnProfile mProfile;
- private OpenVpnService mOpenVPNService;
- private LinkedList<FileDescriptor> mFDList=new LinkedList<FileDescriptor>();
- private int mBytecountinterval=2;
- private long mLastIn=0;
- private long mLastOut=0;
- private LocalServerSocket mServerSocket;
- private boolean mReleaseHold=true;
- private boolean mWaitingForRelease=false;
- private long mLastHoldRelease=0;
-
- private static Vector<OpenVpnManagementThread> active=new Vector<OpenVpnManagementThread>();
-
- static private native void jniclose(int fdint);
- static private native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException;
-
- public OpenVpnManagementThread(VpnProfile profile, LocalServerSocket mgmtsocket, OpenVpnService openVpnService) {
- mProfile = profile;
- mServerSocket = mgmtsocket;
- mOpenVPNService = openVpnService;
-
-
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(openVpnService);
- boolean managemeNetworkState = prefs.getBoolean("netchangereconnect", true);
- if(managemeNetworkState)
- mReleaseHold=false;
-
- }
-
- static {
- System.loadLibrary("opvpnutil");
- }
-
- public void managmentCommand(String cmd) {
- if(mSocket!=null) {
- try {
- mSocket.getOutputStream().write(cmd.getBytes());
- mSocket.getOutputStream().flush();
- } catch (IOException e) {
- // Ignore socket stack traces
- }
- }
- }
-
-
- @Override
- public void run() {
- Log.i(TAG, "Managment Socket Thread started");
- byte [] buffer =new byte[2048];
- // mSocket.setSoTimeout(5); // Setting a timeout cannot be that bad
-
- String pendingInput="";
- active.add(this);
-
- try {
- // Wait for a client to connect
- mSocket= mServerSocket.accept();
- InputStream instream = mSocket.getInputStream();
-
- while(true) {
- int numbytesread = instream.read(buffer);
- if(numbytesread==-1)
- return;
-
- FileDescriptor[] fds = null;
- try {
- fds = mSocket.getAncillaryFileDescriptors();
- } catch (IOException e) {
- OpenVPN.logMessage(0, "", "Error reading fds from socket" + e.getLocalizedMessage());
- e.printStackTrace();
- }
- if(fds!=null){
-
- for (FileDescriptor fd : fds) {
-
- mFDList.add(fd);
- }
- }
-
- String input = new String(buffer,0,numbytesread,"UTF-8");
-
- pendingInput += input;
-
- pendingInput=processInput(pendingInput);
-
-
-
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- active.remove(this);
- }
-
- //! Hack O Rama 2000!
- private void protectFileDescriptor(FileDescriptor fd) {
- Exception exp=null;
- try {
- Method getInt = FileDescriptor.class.getDeclaredMethod("getInt$");
- int fdint = (Integer) getInt.invoke(fd);
-
- // You can even get more evil by parsing toString() and extract the int from that :)
-
- mOpenVPNService.protect(fdint);
-
- //ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(fdint);
- //pfd.close();
- jniclose(fdint);
- return;
- } catch (NoSuchMethodException e) {
- exp =e;
- } catch (IllegalArgumentException e) {
- exp =e;
- } catch (IllegalAccessException e) {
- exp =e;
- } catch (InvocationTargetException e) {
- exp =e;
- } catch (NullPointerException e) {
- exp =e;
- }
- if(exp!=null) {
- exp.printStackTrace();
- Log.d("Openvpn", "Failed to retrieve fd from socket: " + fd);
- OpenVPN.logMessage(0, "", "Failed to retrieve fd from socket: " + exp.getLocalizedMessage());
- }
- }
-
- private String processInput(String pendingInput) {
-
-
- while(pendingInput.contains("\n")) {
- String[] tokens = pendingInput.split("\\r?\\n", 2);
- processCommand(tokens[0]);
- if(tokens.length == 1)
- // No second part, newline was at the end
- pendingInput="";
- else
- pendingInput=tokens[1];
- }
- return pendingInput;
- }
-
-
- private void processCommand(String command) {
- Log.d(TAG, "processCommand: " + command);
-
- if (command.startsWith(">") && command.contains(":")) {
- String[] parts = command.split(":",2);
- String cmd = parts[0].substring(1);
- String argument = parts[1];
- if(cmd.equals("INFO")) {
- // Ignore greeting from mgmt
- //logStatusMessage(command);
- }else if (cmd.equals("PASSWORD")) {
- processPWCommand(argument);
- } else if (cmd.equals("HOLD")) {
- handleHold();
- } else if (cmd.equals("NEED-OK")) {
- processNeedCommand(argument);
- } else if (cmd.equals("BYTECOUNT")){
- processByteCount(argument);
- } else if (cmd.equals("STATE")) {
- processState(argument);
- } else if (cmd.equals("FATAL")){
- processState(","+cmd+","); //handles FATAL as state
- } else if (cmd.equals("PROXY")) {
- processProxyCMD(argument);
- } else if (cmd.equals("LOG")) {
- String[] args = argument.split(",",3);
- // 0 unix time stamp
- // 1 log level N,I,E etc.
- // 2 log message
- OpenVPN.logMessage(0, "", args[2]);
- } else if (cmd.equals("RSA_SIGN")) {
- processSignCommand(argument);
- } else {
- OpenVPN.logMessage(0, "MGMT:", "Got unrecognized command" + command);
- Log.i(TAG, "Got unrecognized command" + command);
- }
- } else if (command.startsWith("SUCCESS:")) { //Fixes bug LEAP #4565
- if (command.equals("SUCCESS: signal SIGINT thrown")){
- Log.d(TAG, "SUCCESS: signal SIGINT thrown");
- processState(",EXITING,SIGINT,,");
- }
- } else {
- Log.i(TAG, "Got unrecognized line from managment" + command);
- OpenVPN.logMessage(0, "MGMT:", "Got unrecognized line from management:" + command);
- }
- }
- private void handleHold() {
- if(mReleaseHold) {
- releaseHoldCmd();
- } else {
- mWaitingForRelease=true;
- OpenVPN.updateStateString("NONETWORK", "",R.string.state_nonetwork);
- }
- }
- private void releaseHoldCmd() {
- if ((System.currentTimeMillis()- mLastHoldRelease) < 5000) {
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {}
-
- }
- mWaitingForRelease=false;
- mLastHoldRelease = System.currentTimeMillis();
- managmentCommand("hold release\n");
- managmentCommand("bytecount " + mBytecountinterval + "\n");
- managmentCommand("state on\n");
- }
-
- public void releaseHold() {
- mReleaseHold=true;
- if(mWaitingForRelease)
- releaseHoldCmd();
-
- }
-
- private void processProxyCMD(String argument) {
- String[] args = argument.split(",",3);
- SocketAddress proxyaddr = ProxyDetection.detectProxy(mProfile);
-
-
- if(args.length >= 2) {
- String proto = args[1];
- if(proto.equals("UDP")) {
- proxyaddr=null;
- }
- }
-
- if(proxyaddr instanceof InetSocketAddress ){
- InetSocketAddress isa = (InetSocketAddress) proxyaddr;
-
- OpenVPN.logInfo(R.string.using_proxy, isa.getHostName(),isa.getPort());
-
- String proxycmd = String.format("proxy HTTP %s %d\n", isa.getHostName(),isa.getPort());
- managmentCommand(proxycmd);
- } else {
- managmentCommand("proxy NONE\n");
- }
-
- }
- private void processState(String argument) {
- String[] args = argument.split(",",3);
- String currentstate = args[1];
- if(args[2].equals(",,")){
- OpenVPN.updateStateString(currentstate,"");
- }
- else if (args[2].endsWith(",,")){ //fixes LEAP Bug #4546
- args[2] = (String) args[2].subSequence(0, args[2].length()-2);
- Log.d(TAG, "processState() STATE: "+ currentstate + " msg: " + args[2]);
- OpenVPN.updateStateString(currentstate,args[2]);
- }
- else{
- OpenVPN.updateStateString(currentstate,args[2]);
- }
- }
-
- private static int repeated_byte_counts = 0;
- private void processByteCount(String argument) {
- // >BYTECOUNT:{BYTES_IN},{BYTES_OUT}
- int comma = argument.indexOf(',');
- long in = Long.parseLong(argument.substring(0, comma));
- long out = Long.parseLong(argument.substring(comma+1));
-
- long diffin = in - mLastIn;
- long diffout = out - mLastOut;
- if(diffin == 0 && diffout == 0)
- repeated_byte_counts++;
- if(repeated_byte_counts > 3)
- Log.d("OpenVPN log", "Repeated byte count = " + repeated_byte_counts);
- mLastIn=in;
- mLastOut=out;
-
- String netstat = String.format("In: %8s, %8s/s Out %8s, %8s/s",
- humanReadableByteCount(in, false),
- humanReadableByteCount(diffin, false),
- humanReadableByteCount(out, false),
- humanReadableByteCount(diffout, false));
- OpenVPN.updateStateString("BYTECOUNT",netstat);
-
-
- }
-
- // From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java
- public static String humanReadableByteCount(long bytes, boolean si) {
- int unit = si ? 1000 : 1024;
- if (bytes < unit) return bytes + " B";
- int exp = (int) (Math.log(bytes) / Math.log(unit));
- String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
- return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
- }
-
- private void processNeedCommand(String argument) {
- int p1 =argument.indexOf('\'');
- int p2 = argument.indexOf('\'',p1+1);
-
- String needed = argument.substring(p1+1, p2);
- String extra = argument.split(":",2)[1];
-
- String status = "ok";
-
-
- if (needed.equals("PROTECTFD")) {
- FileDescriptor fdtoprotect = mFDList.pollFirst();
- protectFileDescriptor(fdtoprotect);
- } else if (needed.equals("DNSSERVER")) {
- mOpenVPNService.addDNS(extra);
- }else if (needed.equals("DNSDOMAIN")){
- mOpenVPNService.setDomain(extra);
- } else if (needed.equals("ROUTE")) {
- String[] routeparts = extra.split(" ");
- mOpenVPNService.addRoute(routeparts[0], routeparts[1]);
- } else if (needed.equals("ROUTE6")) {
- mOpenVPNService.addRoutev6(extra);
- } else if (needed.equals("IFCONFIG")) {
- String[] ifconfigparts = extra.split(" ");
- int mtu = Integer.parseInt(ifconfigparts[2]);
- mOpenVPNService.setLocalIP(ifconfigparts[0], ifconfigparts[1],mtu,ifconfigparts[3]);
- } else if (needed.equals("IFCONFIG6")) {
- mOpenVPNService.setLocalIPv6(extra);
-
- } else if (needed.equals("OPENTUN")) {
- if(sendTunFD(needed,extra))
- return;
- else
- status="cancel";
- // This not nice or anything but setFileDescriptors accepts only FilDescriptor class :(
-
- } else {
- Log.e(TAG,"Unkown needok command " + argument);
- return;
- }
-
- String cmd = String.format("needok '%s' %s\n", needed, status);
- managmentCommand(cmd);
- }
-
- private boolean sendTunFD (String needed, String extra) {
- Exception exp = null;
- if(!extra.equals("tun")) {
- // We only support tun
- String errmsg = String.format("Devicetype %s requested, but only tun is possible with the Android API, sorry!",extra);
- OpenVPN.logMessage(0, "", errmsg );
-
- return false;
- }
- ParcelFileDescriptor pfd = mOpenVPNService.openTun();
- if(pfd==null)
- return false;
-
- Method setInt;
- int fdint = pfd.getFd();
- try {
- setInt = FileDescriptor.class.getDeclaredMethod("setInt$",int.class);
- FileDescriptor fdtosend = new FileDescriptor();
-
- setInt.invoke(fdtosend,fdint);
-
- FileDescriptor[] fds = {fdtosend};
- mSocket.setFileDescriptorsForSend(fds);
-
- Log.d("Openvpn", "Sending FD tosocket: " + fdtosend + " " + fdint + " " + pfd);
- // Trigger a send so we can close the fd on our side of the channel
- // The API documentation fails to mention that it will not reset the file descriptor to
- // be send and will happily send the file descriptor on every write ...
- String cmd = String.format("needok '%s' %s\n", needed, "ok");
- managmentCommand(cmd);
-
- // Set the FileDescriptor to null to stop this mad behavior
- mSocket.setFileDescriptorsForSend(null);
-
- pfd.close();
-
- return true;
- } catch (NoSuchMethodException e) {
- exp =e;
- } catch (IllegalArgumentException e) {
- exp =e;
- } catch (IllegalAccessException e) {
- exp =e;
- } catch (InvocationTargetException e) {
- exp =e;
- } catch (IOException e) {
- exp =e;
- }
- if(exp!=null) {
- OpenVPN.logMessage(0,"", "Could not send fd over socket:" + exp.getLocalizedMessage());
- exp.printStackTrace();
- }
- return false;
- }
-
- private void processPWCommand(String argument) {
- //argument has the form Need 'Private Key' password
- // or ">PASSWORD:Verification Failed: '%s' ['%s']"
- String needed;
-
-
-
- try{
-
- int p1 = argument.indexOf('\'');
- int p2 = argument.indexOf('\'',p1+1);
- needed = argument.substring(p1+1, p2);
- if (argument.startsWith("Verification Failed")) {
- proccessPWFailed(needed, argument.substring(p2+1));
- return;
- }
- } catch (StringIndexOutOfBoundsException sioob) {
- OpenVPN.logMessage(0, "", "Could not parse management Password command: " + argument);
- return;
- }
-
- String pw=null;
-
- if(needed.equals("Private Key")) {
- pw = mProfile.getPasswordPrivateKey();
- } else if (needed.equals("Auth")) {
- String usercmd = String.format("username '%s' %s\n",
- needed, VpnProfile.openVpnEscape(mProfile.mUsername));
- managmentCommand(usercmd);
- pw = mProfile.getPasswordAuth();
- }
- if(pw!=null) {
- String cmd = String.format("password '%s' %s\n", needed, VpnProfile.openVpnEscape(pw));
- managmentCommand(cmd);
- } else {
- OpenVPN.logMessage(0, OpenVPN.MANAGMENT_PREFIX, String.format("Openvpn requires Authentication type '%s' but no password/key information available", needed));
- }
-
- }
-
-
-
-
- private void proccessPWFailed(String needed, String args) {
- OpenVPN.updateStateString("AUTH_FAILED", needed + args,R.string.state_auth_failed);
- }
- private void logStatusMessage(String command) {
- OpenVPN.logMessage(0,"MGMT:", command);
- }
-
-
- public static boolean stopOpenVPN() {
- boolean sendCMD=false;
- for (OpenVpnManagementThread mt: active){
- mt.managmentCommand("signal SIGINT\n");
- sendCMD=true;
- try {
- if(mt.mSocket !=null)
- mt.mSocket.close();
- } catch (IOException e) {
- // Ignore close error on already closed socket
- }
- }
- return sendCMD;
- }
-
- public void signalusr1() {
- mReleaseHold=false;
- if(!mWaitingForRelease)
- managmentCommand("signal SIGUSR1\n");
- }
-
- public void reconnect() {
- signalusr1();
- releaseHold();
- }
-
- private void processSignCommand(String b64data) {
-
- PrivateKey privkey = mProfile.getKeystoreKey();
- Exception err =null;
-
- byte[] data = Base64.decode(b64data, Base64.DEFAULT);
-
- // The Jelly Bean *evil* Hack
- // 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider
- if(Build.VERSION.SDK_INT==16){
- processSignJellyBeans(privkey,data);
- return;
- }
-
-
- try{
-
-
- Cipher rsasinger = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
-
- rsasinger.init(Cipher.ENCRYPT_MODE, privkey);
-
- byte[] signed_bytes = rsasinger.doFinal(data);
- String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP);
- managmentCommand("rsa-sig\n");
- managmentCommand(signed_string);
- managmentCommand("\nEND\n");
- } catch (NoSuchAlgorithmException e){
- err =e;
- } catch (InvalidKeyException e) {
- err =e;
- } catch (NoSuchPaddingException e) {
- err =e;
- } catch (IllegalBlockSizeException e) {
- err =e;
- } catch (BadPaddingException e) {
- err =e;
- }
- if(err !=null) {
- OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage());
- }
-
- }
-
-
- private void processSignJellyBeans(PrivateKey privkey, byte[] data) {
- Exception err =null;
- try {
- Method[] allm = privkey.getClass().getSuperclass().getDeclaredMethods();
- System.out.println(allm);
- Method getKey = privkey.getClass().getSuperclass().getDeclaredMethod("getOpenSSLKey");
- getKey.setAccessible(true);
-
- // Real object type is OpenSSLKey
- Object opensslkey = getKey.invoke(privkey);
-
- getKey.setAccessible(false);
-
- Method getPkeyContext = opensslkey.getClass().getDeclaredMethod("getPkeyContext");
-
- // integer pointer to EVP_pkey
- getPkeyContext.setAccessible(true);
- int pkey = (Integer) getPkeyContext.invoke(opensslkey);
- getPkeyContext.setAccessible(false);
-
- byte[] signed_bytes = rsasign(data, pkey);
- String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP);
- managmentCommand("rsa-sig\n");
- managmentCommand(signed_string);
- managmentCommand("\nEND\n");
-
- } catch (NoSuchMethodException e) {
- err=e;
- } catch (IllegalArgumentException e) {
- err=e;
- } catch (IllegalAccessException e) {
- err=e;
- } catch (InvocationTargetException e) {
- err=e;
- } catch (InvalidKeyException e) {
- err=e;
- }
- if(err !=null) {
- OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage());
- }
-
- }
-}
diff --git a/src/se/leap/openvpn/OpenVpnService.java b/src/se/leap/openvpn/OpenVpnService.java deleted file mode 100644 index b5c9c798..00000000 --- a/src/se/leap/openvpn/OpenVpnService.java +++ /dev/null @@ -1,504 +0,0 @@ -package se.leap.openvpn; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Vector; - -import se.leap.bitmaskclient.Dashboard; -import se.leap.bitmaskclient.R; -import android.annotation.TargetApi; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.LocalServerSocket; -import android.net.LocalSocket; -import android.net.LocalSocketAddress; -import android.net.VpnService; -import android.os.Binder; -import android.os.Handler.Callback; -import android.os.Build; -import android.os.IBinder; -import android.os.Message; -import android.os.ParcelFileDescriptor; -import se.leap.openvpn.OpenVPN.StateListener; - -public class OpenVpnService extends VpnService implements StateListener, Callback { - public static final String START_SERVICE = "se.leap.openvpn.START_SERVICE"; - public static final String RETRIEVE_SERVICE = "se.leap.openvpn.RETRIEVE_SERVICE"; - - private Thread mProcessThread=null; - - private Vector<String> mDnslist=new Vector<String>(); - - private VpnProfile mProfile; - - private String mDomain=null; - - private Vector<CIDRIP> mRoutes=new Vector<CIDRIP>(); - private Vector<String> mRoutesv6=new Vector<String>(); - - private CIDRIP mLocalIP=null; - - private OpenVpnManagementThread mSocketManager; - - private Thread mSocketManagerThread; - private int mMtu; - private String mLocalIPv6=null; - private NetworkSateReceiver mNetworkStateReceiver; - private NotificationManager mNotificationManager; - - private boolean mDisplayBytecount=false; - - private boolean mStarting=false; - - private long mConnecttime; - - - private static final int OPENVPN_STATUS = 1; - - public static final int PROTECT_FD = 0; - - private final IBinder mBinder = new LocalBinder(); - - public class LocalBinder extends Binder { - public OpenVpnService getService() { - // Return this instance of LocalService so clients can call public methods - return OpenVpnService.this; - } - } - - @Override - public IBinder onBind(Intent intent) { - String action = intent.getAction(); - if( action !=null && (action.equals(START_SERVICE) || action.equals(RETRIEVE_SERVICE)) ) - return mBinder; - else - return super.onBind(intent); - } - - @Override - public void onRevoke() { - OpenVpnManagementThread.stopOpenVPN(); - endVpnService(); - } - - // Similar to revoke but do not try to stop process - public void processDied() { - endVpnService(); - } - - private void endVpnService() { - mProcessThread=null; - OpenVPN.logBuilderConfig(null); - ProfileManager.setConntectedVpnProfileDisconnected(this); - if(!mStarting) { - stopSelf(); - stopForeground(true); - } - } - - private void showNotification(String state, String msg, String tickerText, boolean lowpriority, long when, boolean persistant) { - String ns = Context.NOTIFICATION_SERVICE; - mNotificationManager = (NotificationManager) getSystemService(ns); - int icon; - if (state.equals("NOPROCESS") || state.equals("AUTH_FAILED") || state.equals("NONETWORK") || state.equals("EXITING")){ - icon = R.drawable.ic_vpn_disconnected; - }else{ - icon = R.drawable.ic_stat_vpn; - } - - android.app.Notification.Builder nbuilder = new Notification.Builder(this); - - nbuilder.setContentTitle(getString(R.string.notifcation_title,mProfile.mLocation)); - nbuilder.setContentText(msg); - nbuilder.setOnlyAlertOnce(true); - nbuilder.setOngoing(persistant); - nbuilder.setContentIntent(getLogPendingIntent()); - nbuilder.setSmallIcon(icon); - if(when !=0) - nbuilder.setWhen(when); - - - // Try to set the priority available since API 16 (Jellybean) - jbNotificationExtras(lowpriority, nbuilder); - if(tickerText!=null) - nbuilder.setTicker(tickerText); - - @SuppressWarnings("deprecation") - Notification notification = nbuilder.getNotification(); - - - mNotificationManager.notify(OPENVPN_STATUS, notification); - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - private void jbNotificationExtras(boolean lowpriority, - android.app.Notification.Builder nbuilder) { - try { - if(lowpriority) { - Method setpriority = nbuilder.getClass().getMethod("setPriority", int.class); - // PRIORITY_MIN == -2 - setpriority.invoke(nbuilder, -2 ); - - nbuilder.setUsesChronometer(true); - /* PendingIntent cancelconnet=null; - - nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, - getString(R.string.cancel_connection),cancelconnet); */ - } - - //ignore exception - } catch (NoSuchMethodException nsm) { - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { - } catch (InvocationTargetException e) { - } - - } - - PendingIntent getLogPendingIntent() { - // Let the configure Button show the Dashboard - Intent intent = new Intent(Dashboard.getAppContext(),Dashboard.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent startLW = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - return startLW; - - } - - - private LocalServerSocket openManagmentInterface(int tries) { - // Could take a while to open connection - String socketname = (getCacheDir().getAbsolutePath() + "/" + "mgmtsocket"); - LocalSocket sock = new LocalSocket(); - - while(tries > 0 && !sock.isConnected()) { - try { - sock.bind(new LocalSocketAddress(socketname, - LocalSocketAddress.Namespace.FILESYSTEM)); - } catch (IOException e) { - // wait 300 ms before retrying - try { Thread.sleep(300); - } catch (InterruptedException e1) {} - - } - tries--; - } - - try { - LocalServerSocket lss = new LocalServerSocket(sock.getFileDescriptor()); - return lss; - } catch (IOException e) { - e.printStackTrace(); - } - return null; - - - } - - void registerNetworkStateReceiver() { - // Registers BroadcastReceiver to track network connection changes. - IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); - mNetworkStateReceiver = new NetworkSateReceiver(mSocketManager); - this.registerReceiver(mNetworkStateReceiver, filter); - } - - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - - if( intent != null && intent.getAction() !=null && - (intent.getAction().equals(START_SERVICE) || intent.getAction().equals(RETRIEVE_SERVICE)) ) - return START_NOT_STICKY; - - - // Extract information from the intent. - String prefix = getPackageName(); - String[] argv = intent.getStringArrayExtra(prefix + ".ARGV"); - String nativelibdir = intent.getStringExtra(prefix + ".nativelib"); - String profileUUID = intent.getStringExtra(prefix + ".profileUUID"); - - mProfile = ProfileManager.get(profileUUID); - - //showNotification("Starting VPN " + mProfile.mName,"Starting VPN " + mProfile.mName, false,0); - - - OpenVPN.addStateListener(this); - - // Set a flag that we are starting a new VPN - mStarting=true; - // Stop the previous session by interrupting the thread. - if(OpenVpnManagementThread.stopOpenVPN()){ - // an old was asked to exit, wait 2s - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - } - - if (mProcessThread!=null) { - mProcessThread.interrupt(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - } - // An old running VPN should now be exited - mStarting=false; - - - // Open the Management Interface - LocalServerSocket mgmtsocket = openManagmentInterface(8); - - if(mgmtsocket!=null) { - // start a Thread that handles incoming messages of the managment socket - mSocketManager = new OpenVpnManagementThread(mProfile,mgmtsocket,this); - mSocketManagerThread = new Thread(mSocketManager,"OpenVPNMgmtThread"); - mSocketManagerThread.start(); - OpenVPN.logInfo("started Socket Thread"); - registerNetworkStateReceiver(); - } - - - // Start a new session by creating a new thread. - OpenVPNThread processThread = new OpenVPNThread(this, argv,nativelibdir); - - mProcessThread = new Thread(processThread, "OpenVPNProcessThread"); - mProcessThread.start(); - - ProfileManager.setConnectedVpnProfile(this, mProfile); - - return START_NOT_STICKY; - } - - @Override - public void onDestroy() { - if (mProcessThread != null) { - mSocketManager.managmentCommand("signal SIGINT\n"); - - mProcessThread.interrupt(); - } - if (mNetworkStateReceiver!= null) { - this.unregisterReceiver(mNetworkStateReceiver); - } - - } - - - - public ParcelFileDescriptor openTun() { - Builder builder = new Builder(); - - if(mLocalIP==null && mLocalIPv6==null) { - OpenVPN.logMessage(0, "", getString(R.string.opentun_no_ipaddr)); - return null; - } - - if(mLocalIP!=null) { - builder.addAddress(mLocalIP.mIp, mLocalIP.len); - } - - if(mLocalIPv6!=null) { - String[] ipv6parts = mLocalIPv6.split("/"); - builder.addAddress(ipv6parts[0],Integer.parseInt(ipv6parts[1])); - } - - - for (String dns : mDnslist ) { - try { - builder.addDnsServer(dns); - } catch (IllegalArgumentException iae) { - OpenVPN.logError(R.string.dns_add_error, dns,iae.getLocalizedMessage()); - } - } - - - builder.setMtu(mMtu); - - - for (CIDRIP route:mRoutes) { - try { - builder.addRoute(route.mIp, route.len); - } catch (IllegalArgumentException ia) { - OpenVPN.logMessage(0, "", getString(R.string.route_rejected) + route + " " + ia.getLocalizedMessage()); - } - } - - for(String v6route:mRoutesv6) { - try { - String[] v6parts = v6route.split("/"); - builder.addRoute(v6parts[0],Integer.parseInt(v6parts[1])); - } catch (IllegalArgumentException ia) { - OpenVPN.logMessage(0, "", getString(R.string.route_rejected) + v6route + " " + ia.getLocalizedMessage()); - } - } - - if(mDomain!=null) - builder.addSearchDomain(mDomain); - - String bconfig[] = new String[6]; - - bconfig[0]= getString(R.string.last_openvpn_tun_config); - bconfig[1] = getString(R.string.local_ip_info,mLocalIP.mIp,mLocalIP.len,mLocalIPv6, mMtu); - bconfig[2] = getString(R.string.dns_server_info, joinString(mDnslist)); - bconfig[3] = getString(R.string.dns_domain_info, mDomain); - bconfig[4] = getString(R.string.routes_info, joinString(mRoutes)); - bconfig[5] = getString(R.string.routes_info6, joinString(mRoutesv6)); - - String session = mProfile.mLocation; - /* we don't want the IP address in the notification bar - if(mLocalIP!=null && mLocalIPv6!=null) - session = getString(R.string.session_ipv6string,session, mLocalIP, mLocalIPv6); - else if (mLocalIP !=null) - session= getString(R.string.session_ipv4string, session, mLocalIP); - */ - builder.setSession(session); - - - OpenVPN.logBuilderConfig(bconfig); - - // No DNS Server, log a warning - if(mDnslist.size()==0) - OpenVPN.logInfo(R.string.warn_no_dns); - - // Reset information - mDnslist.clear(); - mRoutes.clear(); - mRoutesv6.clear(); - mLocalIP=null; - mLocalIPv6=null; - mDomain=null; - - builder.setConfigureIntent(getLogPendingIntent()); - - try { - ParcelFileDescriptor pfd = builder.establish(); - return pfd; - } catch (Exception e) { - OpenVPN.logMessage(0, "", getString(R.string.tun_open_error)); - OpenVPN.logMessage(0, "", getString(R.string.error) + e.getLocalizedMessage()); - OpenVPN.logMessage(0, "", getString(R.string.tun_error_helpful)); - return null; - } - - } - - - // Ugly, but java has no such method - private <T> String joinString(Vector<T> vec) { - String ret = ""; - if(vec.size() > 0){ - ret = vec.get(0).toString(); - for(int i=1;i < vec.size();i++) { - ret = ret + ", " + vec.get(i).toString(); - } - } - return ret; - } - - - - - - - public void addDNS(String dns) { - mDnslist.add(dns); - } - - - public void setDomain(String domain) { - if(mDomain==null) { - mDomain=domain; - } - } - - - public void addRoute(String dest, String mask) { - CIDRIP route = new CIDRIP(dest, mask); - if(route.len == 32 && !mask.equals("255.255.255.255")) { - OpenVPN.logMessage(0, "", getString(R.string.route_not_cidr,dest,mask)); - } - - if(route.normalise()) - OpenVPN.logMessage(0, "", getString(R.string.route_not_netip,dest,route.len,route.mIp)); - - mRoutes.add(route); - } - - public void addRoutev6(String extra) { - mRoutesv6.add(extra); - } - - - public void setLocalIP(String local, String netmask,int mtu, String mode) { - mLocalIP = new CIDRIP(local, netmask); - mMtu = mtu; - - if(mLocalIP.len == 32 && !netmask.equals("255.255.255.255")) { - // get the netmask as IP - long netint = CIDRIP.getInt(netmask); - if(Math.abs(netint - mLocalIP.getInt()) ==1) { - if(mode.equals("net30")) - mLocalIP.len=30; - else - mLocalIP.len=31; - } else { - OpenVPN.logMessage(0, "", getString(R.string.ip_not_cidr, local,netmask,mode)); - } - } - } - - public void setLocalIPv6(String ipv6addr) { - mLocalIPv6 = ipv6addr; - } - - public boolean isRunning() { - if (mStarting == true || mProcessThread != null) - return true; - else - return false; - } - - @Override - public void updateState(String state,String logmessage, int resid) { - // If the process is not running, ignore any state, - // Notification should be invisible in this state - if(mProcessThread==null) - return; - if("CONNECTED".equals(state)) { - mNotificationManager.cancel(OPENVPN_STATUS); - } else if(!"BYTECOUNT".equals(state)) { - - // Other notifications are shown, - // This also mean we are no longer connected, ignore bytecount messages until next - // CONNECTED - String ticker = getString(resid); - boolean persist = false; - if (("NOPROCESS".equals(state) ) || ("EXITING").equals(state)){ - showNotification(state, getString(R.string.eip_state_not_connected), ticker, false, 0, persist); - } - else if (state.equals("GET_CONFIG") || state.equals("ASSIGN_IP")){ //don't show them in the notification message - } - else{ - persist = true; - showNotification(state, getString(resid) +" " + logmessage,ticker,false,0,persist); - } - } - } - - @Override - public boolean handleMessage(Message msg) { - Runnable r = msg.getCallback(); - if(r!=null){ - r.run(); - return true; - } else { - return false; - } - } -} diff --git a/src/se/leap/openvpn/ProfileManager.java b/src/se/leap/openvpn/ProfileManager.java deleted file mode 100644 index b9eb3ab6..00000000 --- a/src/se/leap/openvpn/ProfileManager.java +++ /dev/null @@ -1,220 +0,0 @@ -package se.leap.openvpn; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.StreamCorruptedException; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.preference.PreferenceManager; - -public class ProfileManager { - private static final String PREFS_NAME = "VPNList"; - - - - private static final String ONBOOTPROFILE = "onBootProfile"; - - - - private static ProfileManager instance; - - - - private static VpnProfile mLastConnectedVpn=null; - private HashMap<String,VpnProfile> profiles=new HashMap<String, VpnProfile>(); - private static VpnProfile tmpprofile=null; - - - public static VpnProfile get(String key) { - if (tmpprofile!=null && tmpprofile.getUUIDString().equals(key)) - return tmpprofile; - - if(instance==null) - return null; - return instance.profiles.get(key); - - } - - - - private ProfileManager() { } - - private static void checkInstance(Context context) { - if(instance == null) { - instance = new ProfileManager(); - instance.loadVPNList(context); - } - } - - synchronized public static ProfileManager getInstance(Context context) { - checkInstance(context); - return instance; - } - - public static void setConntectedVpnProfileDisconnected(Context c) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - Editor prefsedit = prefs.edit(); - prefsedit.putString(ONBOOTPROFILE, null); - prefsedit.apply(); - - } - - public static void setConnectedVpnProfile(Context c, VpnProfile connectedrofile) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - Editor prefsedit = prefs.edit(); - - prefsedit.putString(ONBOOTPROFILE, connectedrofile.getUUIDString()); - prefsedit.apply(); - mLastConnectedVpn=connectedrofile; - - } - - public static VpnProfile getOnBootProfile(Context c) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - - boolean useStartOnBoot = prefs.getBoolean("restartvpnonboot", false); - - - String mBootProfileUUID = prefs.getString(ONBOOTPROFILE,null); - if(useStartOnBoot && mBootProfileUUID!=null) - return get(c, mBootProfileUUID); - else - return null; - } - - - - - public Collection<VpnProfile> getProfiles() { - return profiles.values(); - } - - public VpnProfile getProfileByName(String name) { - for (VpnProfile vpnp : profiles.values()) { - if(vpnp.getName().equals(name)) { - return vpnp; - } - } - return null; - } - - public void saveProfileList(Context context) { - SharedPreferences sharedprefs = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); - Editor editor = sharedprefs.edit(); - editor.putStringSet("vpnlist", profiles.keySet()); - - // For reasing I do not understand at all - // Android saves my prefs file only one time - // if I remove the debug code below :( - int counter = sharedprefs.getInt("counter", 0); - editor.putInt("counter", counter+1); - editor.apply(); - - } - - public void addProfile(VpnProfile profile) { - profiles.put(profile.getUUID().toString(),profile); - - } - - public static void setTemporaryProfile(VpnProfile tmp) { - ProfileManager.tmpprofile = tmp; - } - - - public void saveProfile(Context context,VpnProfile profile) { - // First let basic settings save its state - - ObjectOutputStream vpnfile; - try { - vpnfile = new ObjectOutputStream(context.openFileOutput((profile.getUUID().toString() + ".vp"),Activity.MODE_PRIVATE)); - - vpnfile.writeObject(profile); - vpnfile.flush(); - vpnfile.close(); - } catch (FileNotFoundException e) { - - e.printStackTrace(); - throw new RuntimeException(e); - } catch (IOException e) { - - e.printStackTrace(); - throw new RuntimeException(e); - - } - } - - - private void loadVPNList(Context context) { - profiles = new HashMap<String, VpnProfile>(); - SharedPreferences listpref = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); - Set<String> vlist = listpref.getStringSet("vpnlist", null); - Exception exp =null; - if(vlist==null){ - vlist = new HashSet<String>(); - } - - for (String vpnentry : vlist) { - try { - ObjectInputStream vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp")); - VpnProfile vp = ((VpnProfile) vpnfile.readObject()); - - // Sanity check - if(vp==null || vp.mName==null || vp.getUUID()==null) - continue; - - profiles.put(vp.getUUID().toString(), vp); - - } catch (StreamCorruptedException e) { - exp=e; - } catch (FileNotFoundException e) { - exp=e; - } catch (IOException e) { - exp=e; - } catch (ClassNotFoundException e) { - exp=e; - } - if(exp!=null) { - exp.printStackTrace(); - } - } - } - - public int getNumberOfProfiles() { - return profiles.size(); - } - - - - public void removeProfile(Context context,VpnProfile profile) { - String vpnentry = profile.getUUID().toString(); - profiles.remove(vpnentry); - saveProfileList(context); - context.deleteFile(vpnentry + ".vp"); - if(mLastConnectedVpn==profile) - mLastConnectedVpn=null; - - } - - - - public static VpnProfile get(Context context, String profileUUID) { - checkInstance(context); - return get(profileUUID); - } - - - - public static VpnProfile getLastConnectedVpn() { - return mLastConnectedVpn; - } - -} diff --git a/src/se/leap/openvpn/ProxyDetection.java b/src/se/leap/openvpn/ProxyDetection.java deleted file mode 100644 index c7b3d196..00000000 --- a/src/se/leap/openvpn/ProxyDetection.java +++ /dev/null @@ -1,54 +0,0 @@ -package se.leap.openvpn; - -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.Proxy; -import java.net.ProxySelector; -import java.net.SocketAddress; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.List; - -import se.leap.bitmaskclient.R; - -public class ProxyDetection { - static SocketAddress detectProxy(VpnProfile vp) { - // Construct a new url with https as protocol - try { - URL url = new URL(String.format("https://%s:%s",vp.mServerName,vp.mServerPort)); - Proxy proxy = getFirstProxy(url); - - if(proxy==null) - return null; - SocketAddress addr = proxy.address(); - if (addr instanceof InetSocketAddress) { - return addr; - } - - } catch (MalformedURLException e) { - OpenVPN.logError(R.string.getproxy_error,e.getLocalizedMessage()); - } catch (URISyntaxException e) { - OpenVPN.logError(R.string.getproxy_error,e.getLocalizedMessage()); - } - return null; - } - - static Proxy getFirstProxy(URL url) throws URISyntaxException { - System.setProperty("java.net.useSystemProxies", "true"); - - List<Proxy> proxylist = ProxySelector.getDefault().select(url.toURI()); - - - if (proxylist != null) { - for (Proxy proxy: proxylist) { - SocketAddress addr = proxy.address(); - - if (addr != null) { - return proxy; - } - } - - } - return null; - } -}
\ No newline at end of file diff --git a/src/se/leap/openvpn/VPNLaunchHelper.java b/src/se/leap/openvpn/VPNLaunchHelper.java deleted file mode 100644 index 418cf7e9..00000000 --- a/src/se/leap/openvpn/VPNLaunchHelper.java +++ /dev/null @@ -1,76 +0,0 @@ -package se.leap.openvpn; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import se.leap.bitmaskclient.R; - -import android.content.Context; -import android.content.Intent; -import android.os.Build; - -public class VPNLaunchHelper { - static private boolean writeMiniVPN(Context context) { - File mvpnout = new File(context.getCacheDir(),VpnProfile.MINIVPN); - if (mvpnout.exists() && mvpnout.canExecute()) - return true; - - IOException e2 = null; - - try { - InputStream mvpn; - - try { - mvpn = context.getAssets().open("minivpn." + Build.CPU_ABI); - } - catch (IOException errabi) { - OpenVPN.logInfo("Failed getting assets for archicture " + Build.CPU_ABI); - e2=errabi; - mvpn = context.getAssets().open("minivpn." + Build.CPU_ABI2); - - } - - - FileOutputStream fout = new FileOutputStream(mvpnout); - - byte buf[]= new byte[4096]; - - int lenread = mvpn.read(buf); - while(lenread> 0) { - fout.write(buf, 0, lenread); - lenread = mvpn.read(buf); - } - fout.close(); - - if(!mvpnout.setExecutable(true)) { - OpenVPN.logMessage(0, "","Failed to set minivpn executable"); - return false; - } - - - return true; - } catch (IOException e) { - if(e2!=null) - OpenVPN.logMessage(0, "",e2.getLocalizedMessage()); - OpenVPN.logMessage(0, "",e.getLocalizedMessage()); - e.printStackTrace(); - return false; - } - } - - - public static void startOpenVpn(VpnProfile startprofile, Context context) { - if(!writeMiniVPN(context)) { - OpenVPN.logMessage(0, "", "Error writing minivpn binary"); - return; - } - OpenVPN.logMessage(0, "", context.getString(R.string.building_configration)); - - Intent startVPN = startprofile.prepareIntent(context); - if(startVPN!=null) - context.startService(startVPN); - - } -} diff --git a/src/se/leap/openvpn/VpnProfile.java b/src/se/leap/openvpn/VpnProfile.java deleted file mode 100644 index 481819ad..00000000 --- a/src/se/leap/openvpn/VpnProfile.java +++ /dev/null @@ -1,758 +0,0 @@ -package se.leap.openvpn; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Collection; -import java.util.UUID; -import java.util.Vector; - -import org.spongycastle.util.io.pem.PemObject; -import org.spongycastle.util.io.pem.PemWriter; - -import se.leap.bitmaskclient.ConfigHelper; -import se.leap.bitmaskclient.Dashboard; -import se.leap.bitmaskclient.EIP; -import se.leap.bitmaskclient.Provider; -import se.leap.bitmaskclient.R; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.preference.PreferenceManager; -import android.security.KeyChain; -import android.security.KeyChainException; - -public class VpnProfile implements Serializable{ - // Parcable - /** - * - */ - private static final long serialVersionUID = 7085688938959334563L; - static final int TYPE_CERTIFICATES=0; - static final int TYPE_PKCS12=1; - static final int TYPE_KEYSTORE=2; - public static final int TYPE_USERPASS = 3; - public static final int TYPE_STATICKEYS = 4; - public static final int TYPE_USERPASS_CERTIFICATES = 5; - public static final int TYPE_USERPASS_PKCS12 = 6; - public static final int TYPE_USERPASS_KEYSTORE = 7; - - // Don't change this, not all parts of the program use this constant - public static final String EXTRA_PROFILEUUID = "se.leap.bitmaskclient.profileUUID"; // TODO this feels wrong. See Issue #1494 - public static final String INLINE_TAG = "[[INLINE]]"; - private static final String OVPNCONFIGFILE = "android.conf"; - - protected transient String mTransientPW=null; - protected transient String mTransientPCKS12PW=null; - private transient PrivateKey mPrivateKey; - protected boolean profileDleted=false; - - - public static String DEFAULT_DNS1="131.234.137.23"; - public static String DEFAULT_DNS2="131.234.137.24"; - - // Public attributes, since I got mad with getter/setter - // set members to default values - private UUID mUuid; - public int mAuthenticationType = TYPE_CERTIFICATES ; - public String mName; - public String mLocation; - public String mAlias; - public String mClientCertFilename; - public String mTLSAuthDirection=""; - public String mTLSAuthFilename; - public String mClientKeyFilename; - public String mCaFilename; - public boolean mUseLzo=true; - public String mServerPort= "1194" ; - public boolean mUseUdp = true; - public String mPKCS12Filename; - public String mPKCS12Password; - public boolean mUseTLSAuth = false; - public String mServerName = "openvpn.blinkt.de" ; - public String mDNS1=DEFAULT_DNS1; - public String mDNS2=DEFAULT_DNS2; - public String mIPv4Address; - public String mIPv6Address; - public boolean mOverrideDNS=false; - public String mSearchDomain="blinkt.de"; - public boolean mUseDefaultRoute=true; - public boolean mUsePull=true; - public String mCustomRoutes; - public boolean mCheckRemoteCN=false; - public boolean mExpectTLSCert=true; - public String mRemoteCN=""; - public String mPassword=""; - public String mUsername=""; - public boolean mRoutenopull=false; - public boolean mUseRandomHostname=false; - public boolean mUseFloat=false; - public boolean mUseCustomConfig=false; - public String mCustomConfigOptions=""; - public String mVerb="1"; - public String mCipher=""; - public boolean mNobind=false; - public boolean mUseDefaultRoutev6=true; - public String mCustomRoutesv6=""; - public String mKeyPassword=""; - public boolean mPersistTun = false; - public String mConnectRetryMax="5"; - public String mConnectRetry="10"; - public boolean mUserEditable=true; - - static final String MINIVPN = "miniopenvpn"; - - - - - - - public void clearDefaults() { - mServerName="unkown"; - mUsePull=false; - mUseLzo=false; - mUseDefaultRoute=false; - mUseDefaultRoutev6=false; - mExpectTLSCert=false; - mPersistTun = false; - } - - - public static String openVpnEscape(String unescaped) { - if(unescaped==null) - return null; - String escapedString = unescaped.replace("\\", "\\\\"); - escapedString = escapedString.replace("\"","\\\""); - escapedString = escapedString.replace("\n","\\n"); - - if (escapedString.equals(unescaped) && !escapedString.contains(" ") && !escapedString.contains("#")) - return unescaped; - else - return '"' + escapedString + '"'; - } - - - static final String OVPNCONFIGCA = "android-ca.pem"; - static final String OVPNCONFIGUSERCERT = "android-user.pem"; - - - public VpnProfile(String name) { - mUuid = UUID.randomUUID(); - mName = name; - } - - public UUID getUUID() { - return mUuid; - - } - - public String getName() { - return mName; - } - - - public String getConfigFile(Context context) - { - - File cacheDir= context.getCacheDir(); - String cfg=""; - - // Enable managment interface - cfg += "# Enables connection to GUI\n"; - cfg += "management "; - - cfg +=cacheDir.getAbsolutePath() + "/" + "mgmtsocket"; - cfg += " unix\n"; - cfg += "management-client\n"; - // Not needed, see updated man page in 2.3 - //cfg += "management-signal\n"; - cfg += "management-query-passwords\n"; - cfg += "management-hold\n\n"; - - /* tmp-dir patched out :) - cfg+="# /tmp does not exist on Android\n"; - cfg+="tmp-dir "; - cfg+=cacheDir.getAbsolutePath(); - cfg+="\n\n"; */ - - cfg+="# Log window is better readable this way\n"; - cfg+="suppress-timestamps\n"; - - - - boolean useTLSClient = (mAuthenticationType != TYPE_STATICKEYS); - - if(useTLSClient && mUsePull) - cfg+="client\n"; - else if (mUsePull) - cfg+="pull\n"; - else if(useTLSClient) - cfg+="tls-client\n"; - - - cfg+="verb " + mVerb + "\n"; - - if(mConnectRetryMax ==null) { - mConnectRetryMax="5"; - } - - if(!mConnectRetryMax.equals("-1")) - cfg+="connect-retry-max " + mConnectRetryMax+ "\n"; - - if(mConnectRetry==null) - mConnectRetry="10"; - - - cfg+="connect-retry " + mConnectRetry + "\n"; - - cfg+="resolv-retry 60\n"; - - - - // We cannot use anything else than tun - cfg+="dev tun\n"; - - // Server Address - cfg+="remote "; - cfg+=mServerName; - cfg+=" "; - cfg+=mServerPort; - if(mUseUdp) - cfg+=" udp\n"; - else - cfg+=" tcp-client\n"; - - - - - switch(mAuthenticationType) { - case VpnProfile.TYPE_USERPASS_CERTIFICATES: - cfg+="auth-user-pass\n"; - case VpnProfile.TYPE_CERTIFICATES: - /*// Ca - cfg+=insertFileData("ca",mCaFilename); - - // Client Cert + Key - cfg+=insertFileData("key",mClientKeyFilename); - cfg+=insertFileData("cert",mClientCertFilename); -*/ - // FIXME This is all we need...The whole switch statement can go... - SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE); - cfg+="<ca>\n"+preferences.getString(Provider.CA_CERT, "")+"\n</ca>\n"; - cfg+="<key>\n"+preferences.getString(EIP.PRIVATE_KEY, "")+"\n</key>\n"; - cfg+="<cert>\n"+preferences.getString(EIP.CERTIFICATE, "")+"\n</cert>\n"; - - break; - case VpnProfile.TYPE_USERPASS_PKCS12: - cfg+="auth-user-pass\n"; - case VpnProfile.TYPE_PKCS12: - cfg+=insertFileData("pkcs12",mPKCS12Filename); - break; - - case VpnProfile.TYPE_USERPASS_KEYSTORE: - cfg+="auth-user-pass\n"; - case VpnProfile.TYPE_KEYSTORE: - cfg+="ca " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGCA + "\n"; - cfg+="cert " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGUSERCERT + "\n"; - cfg+="management-external-key\n"; - - break; - case VpnProfile.TYPE_USERPASS: - cfg+="auth-user-pass\n"; - cfg+=insertFileData("ca",mCaFilename); - } - - if(mUseLzo) { - cfg+="comp-lzo\n"; - } - - if(mUseTLSAuth) { - if(mAuthenticationType==TYPE_STATICKEYS) - cfg+=insertFileData("secret",mTLSAuthFilename); - else - cfg+=insertFileData("tls-auth",mTLSAuthFilename); - - if(nonNull(mTLSAuthDirection)) { - cfg+= "key-direction "; - cfg+= mTLSAuthDirection; - cfg+="\n"; - } - - } - - if(!mUsePull ) { - if(nonNull(mIPv4Address)) - cfg +="ifconfig " + cidrToIPAndNetmask(mIPv4Address) + "\n"; - - if(nonNull(mIPv6Address)) - cfg +="ifconfig-ipv6 " + mIPv6Address + "\n"; - } - - if(mUsePull && mRoutenopull) - cfg += "route-nopull\n"; - - String routes = ""; - int numroutes=0; - if(mUseDefaultRoute) - routes += "route 0.0.0.0 0.0.0.0\n"; - else - for(String route:getCustomRoutes()) { - routes += "route " + route + "\n"; - numroutes++; - } - - - if(mUseDefaultRoutev6) - cfg += "route-ipv6 ::/0\n"; - else - for(String route:getCustomRoutesv6()) { - routes += "route-ipv6 " + route + "\n"; - numroutes++; - } - - // Round number to next 100 - if(numroutes> 90) { - numroutes = ((numroutes / 100)+1) * 100; - cfg+="# Alot of routes are set, increase max-routes\n"; - cfg+="max-routes " + numroutes + "\n"; - } - cfg+=routes; - - if(mOverrideDNS || !mUsePull) { - if(nonNull(mDNS1)) - cfg+="dhcp-option DNS " + mDNS1 + "\n"; - if(nonNull(mDNS2)) - cfg+="dhcp-option DNS " + mDNS2 + "\n"; - if(nonNull(mSearchDomain)) - cfg+="dhcp-option DOMAIN " + mSearchDomain + "\n"; - - } - - if(mNobind) - cfg+="nobind\n"; - - - - // Authentication - if(mCheckRemoteCN) { - if(mRemoteCN == null || mRemoteCN.equals("") ) - cfg+="tls-remote " + mServerName + "\n"; - else - cfg += "tls-remote " + openVpnEscape(mRemoteCN) + "\n"; - } - if(mExpectTLSCert) - cfg += "remote-cert-tls server\n"; - - - if(nonNull(mCipher)){ - cfg += "cipher " + mCipher + "\n"; - } - - - // Obscure Settings dialog - if(mUseRandomHostname) - cfg += "#my favorite options :)\nremote-random-hostname\n"; - - if(mUseFloat) - cfg+= "float\n"; - - if(mPersistTun) { - cfg+= "persist-tun\n"; - cfg+= "# persist-tun also sets persist-remote-ip to avoid DNS resolve problem\n"; - cfg+= "persist-remote-ip\n"; - } - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean usesystemproxy = prefs.getBoolean("usesystemproxy", true); - if(usesystemproxy) { - cfg+= "# Use system proxy setting\n"; - cfg+= "management-query-proxy\n"; - } - - - if(mUseCustomConfig) { - cfg += "# Custom configuration options\n"; - cfg += "# You are on your on own here :)\n"; - cfg += mCustomConfigOptions; - cfg += "\n"; - - } - - - - return cfg; - } - - //! Put inline data inline and other data as normal escaped filename - private String insertFileData(String cfgentry, String filedata) { - if(filedata==null) { - return String.format("%s %s\n",cfgentry,"missing"); - }else if(filedata.startsWith(VpnProfile.INLINE_TAG)){ - String datawoheader = filedata.substring(VpnProfile.INLINE_TAG.length()); - return String.format("<%s>\n%s\n</%s>\n",cfgentry,datawoheader,cfgentry); - } else { - return String.format("%s %s\n",cfgentry,openVpnEscape(filedata)); - } - } - - private boolean nonNull(String val) { - if(val == null || val.equals("")) - return false; - else - return true; - } - - private Collection<String> getCustomRoutes() { - Vector<String> cidrRoutes=new Vector<String>(); - if(mCustomRoutes==null) { - // No routes set, return empty vector - return cidrRoutes; - } - for(String route:mCustomRoutes.split("[\n \t]")) { - if(!route.equals("")) { - String cidrroute = cidrToIPAndNetmask(route); - if(cidrRoutes == null) - return null; - - cidrRoutes.add(cidrroute); - } - } - - return cidrRoutes; - } - - private Collection<String> getCustomRoutesv6() { - Vector<String> cidrRoutes=new Vector<String>(); - if(mCustomRoutesv6==null) { - // No routes set, return empty vector - return cidrRoutes; - } - for(String route:mCustomRoutesv6.split("[\n \t]")) { - if(!route.equals("")) { - cidrRoutes.add(route); - } - } - - return cidrRoutes; - } - - - - private String cidrToIPAndNetmask(String route) { - String[] parts = route.split("/"); - - // No /xx, assume /32 as netmask - if (parts.length ==1) - parts = (route + "/32").split("/"); - - if (parts.length!=2) - return null; - int len; - try { - len = Integer.parseInt(parts[1]); - } catch(NumberFormatException ne) { - return null; - } - if (len <0 || len >32) - return null; - - - long nm = 0xffffffffl; - nm = (nm << (32-len)) & 0xffffffffl; - - String netmask =String.format("%d.%d.%d.%d", (nm & 0xff000000) >> 24,(nm & 0xff0000) >> 16, (nm & 0xff00) >> 8 ,nm & 0xff ); - return parts[0] + " " + netmask; - } - - - - private String[] buildOpenvpnArgv(File cacheDir) - { - Vector<String> args = new Vector<String>(); - - // Add fixed paramenters - //args.add("/data/data/se.leap.openvpn/lib/openvpn"); - args.add(cacheDir.getAbsolutePath() +"/" + VpnProfile.MINIVPN); - - args.add("--config"); - args.add(cacheDir.getAbsolutePath() + "/" + OVPNCONFIGFILE); - // Silences script security warning - - args.add("script-security"); - args.add("0"); - - - return (String[]) args.toArray(new String[args.size()]); - } - - public Intent prepareIntent(Context context) { - String prefix = context.getPackageName(); - - Intent intent = new Intent(context,OpenVpnService.class); - - if(mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { - /*if(!saveCertificates(context)) - return null;*/ - } - - intent.putExtra(prefix + ".ARGV" , buildOpenvpnArgv(context.getCacheDir())); - intent.putExtra(prefix + ".profileUUID", mUuid.toString()); - - ApplicationInfo info = context.getApplicationInfo(); - intent.putExtra(prefix +".nativelib",info.nativeLibraryDir); - - try { - FileWriter cfg = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); - cfg.write(getConfigFile(context)); - cfg.flush(); - cfg.close(); - } catch (IOException e) { - e.printStackTrace(); - } - - return intent; - } - - private boolean saveCertificates(Context context) { - PrivateKey privateKey = null; - X509Certificate[] cachain=null; - try { - privateKey = KeyChain.getPrivateKey(context,mAlias); - mPrivateKey = privateKey; - - cachain = KeyChain.getCertificateChain(context, mAlias); - if(cachain.length <= 1 && !nonNull(mCaFilename)) - OpenVPN.logMessage(0, "", context.getString(R.string.keychain_nocacert)); - - for(X509Certificate cert:cachain) { - OpenVPN.logInfo(R.string.cert_from_keystore,cert.getSubjectDN()); - } - - - - - if(nonNull(mCaFilename)) { - try { - Certificate cacert = getCacertFromFile(); - X509Certificate[] newcachain = new X509Certificate[cachain.length+1]; - for(int i=0;i<cachain.length;i++) - newcachain[i]=cachain[i]; - - newcachain[cachain.length-1]=(X509Certificate) cacert; - - } catch (Exception e) { - OpenVPN.logError("Could not read CA certificate" + e.getLocalizedMessage()); - } - } - - - FileWriter fout = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGCA); - PemWriter pw = new PemWriter(fout); - for(X509Certificate cert:cachain) { - pw.writeObject(new PemObject("CERTIFICATE", cert.getEncoded())); - } - - pw.close(); - - - if(cachain.length>= 1){ - X509Certificate usercert = cachain[0]; - - FileWriter userout = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGUSERCERT); - - PemWriter upw = new PemWriter(userout); - upw.writeObject(new PemObject("CERTIFICATE", usercert.getEncoded())); - upw.close(); - - } - - return true; - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (CertificateException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (KeyChainException e) { - OpenVPN.logMessage(0,"",context.getString(R.string.keychain_access)); - } - return false; - } - private Certificate getCacertFromFile() throws FileNotFoundException, CertificateException { - CertificateFactory certFact = CertificateFactory.getInstance("X.509"); - - InputStream inStream; - - if(mCaFilename.startsWith(INLINE_TAG)) - inStream = new ByteArrayInputStream(mCaFilename.replace(INLINE_TAG,"").getBytes()); - else - inStream = new FileInputStream(mCaFilename); - - return certFact.generateCertificate(inStream); - } - - - //! Return an error if somethign is wrong - public int checkProfile(Context context) { -/* if(mAuthenticationType==TYPE_KEYSTORE || mAuthenticationType==TYPE_USERPASS_KEYSTORE) { - if(mAlias==null) - return R.string.no_keystore_cert_selected; - }*/ - - if(!mUsePull) { - if(mIPv4Address == null || cidrToIPAndNetmask(mIPv4Address) == null) - return R.string.ipv4_format_error; - } - if(isUserPWAuth() && !nonNull(mUsername)) { - return R.string.error_empty_username; - } - if(!mUseDefaultRoute && getCustomRoutes()==null) - return R.string.custom_route_format_error; - - // Everything okay - return R.string.no_error_found; - - } - - //! Openvpn asks for a "Private Key", this should be pkcs12 key - // - public String getPasswordPrivateKey() { - if(mTransientPCKS12PW!=null) { - String pwcopy = mTransientPCKS12PW; - mTransientPCKS12PW=null; - return pwcopy; - } - switch (mAuthenticationType) { - case TYPE_PKCS12: - case TYPE_USERPASS_PKCS12: - return mPKCS12Password; - - case TYPE_CERTIFICATES: - case TYPE_USERPASS_CERTIFICATES: - return mKeyPassword; - - case TYPE_USERPASS: - case TYPE_STATICKEYS: - default: - return null; - } - } - private boolean isUserPWAuth() { - switch(mAuthenticationType) { - case TYPE_USERPASS: - case TYPE_USERPASS_CERTIFICATES: - case TYPE_USERPASS_KEYSTORE: - case TYPE_USERPASS_PKCS12: - return true; - default: - return false; - - } - } - - - public boolean requireTLSKeyPassword() { - if(!nonNull(mClientKeyFilename)) - return false; - - String data = ""; - if(mClientKeyFilename.startsWith(INLINE_TAG)) - data = mClientKeyFilename; - else { - char[] buf = new char[2048]; - FileReader fr; - try { - fr = new FileReader(mClientKeyFilename); - int len = fr.read(buf); - while(len > 0 ) { - data += new String(buf,0,len); - len = fr.read(buf); - } - fr.close(); - } catch (FileNotFoundException e) { - return false; - } catch (IOException e) { - return false; - } - - } - - if(data.contains("Proc-Type: 4,ENCRYPTED")) - return true; - else if(data.contains("-----BEGIN ENCRYPTED PRIVATE KEY-----")) - return true; - else - return false; - } - - public int needUserPWInput() { - if((mAuthenticationType == TYPE_PKCS12 || mAuthenticationType == TYPE_USERPASS_PKCS12)&& - (mPKCS12Password == null || mPKCS12Password.equals(""))) { - if(mTransientPCKS12PW==null) - return R.string.pkcs12_file_encryption_key; - } - - if(mAuthenticationType == TYPE_CERTIFICATES || mAuthenticationType == TYPE_USERPASS_CERTIFICATES) { - if(requireTLSKeyPassword() && !nonNull(mKeyPassword)) - if(mTransientPCKS12PW==null) { - return R.string.private_key_password; - } - } - - if(isUserPWAuth() && (mPassword.equals("") || mPassword == null)) { - if(mTransientPW==null) - return R.string.password; - - } - return 0; - } - - public String getPasswordAuth() { - if(mTransientPW!=null) { - String pwcopy = mTransientPW; - mTransientPW=null; - return pwcopy; - } else { - return mPassword; - } - } - - - // Used by the Array Adapter - @Override - public String toString() { - return mName; - } - - - public String getUUIDString() { - return mUuid.toString(); - } - - - public PrivateKey getKeystoreKey() { - return mPrivateKey; - } - - - -} - - - - |