diff options
author | Parménides GV <parmegv@sdf.org> | 2015-04-10 11:19:03 +0200 |
---|---|---|
committer | Parménides GV <parmegv@sdf.org> | 2015-04-10 11:19:03 +0200 |
commit | 1f41fec6765e49838141ad29151713c7ac3dd17c (patch) | |
tree | d4c63d5bbb8e51d91d75179ad01abd9a7565badc /app/src/main/java | |
parent | c198dbd9dd583d980ae7e70118f67d09bed8de55 (diff) | |
parent | fe95b7693f0f1f90d23ba2596ad3b11195efb11d (diff) |
Merge branch 'develop'0.9.3
Diffstat (limited to 'app/src/main/java')
28 files changed, 2011 insertions, 1908 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/AboutActivity.java b/app/src/main/java/se/leap/bitmaskclient/AboutActivity.java index 6c4e517b..ce762fcc 100644 --- a/app/src/main/java/se/leap/bitmaskclient/AboutActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/AboutActivity.java @@ -1,35 +1,35 @@ package se.leap.bitmaskclient; -import android.app.Activity; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Bundle; -import android.widget.TextView; - -public class AboutActivity extends Activity { - +import android.app.*; +import android.content.pm.*; +import android.content.pm.PackageManager.*; +import android.os.*; +import android.widget.*; + +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); + 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/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index c0f0b0c3..4929f040 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -1,6 +1,6 @@ /** * 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 @@ -16,179 +16,170 @@ */ package se.leap.bitmaskclient; -import android.util.Base64; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -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 android.util.*; + +import org.json.*; + +import java.io.*; +import java.math.*; +import java.security.*; +import java.security.cert.*; +import java.security.interfaces.*; +import java.security.spec.*; /** * 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"; + "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; - } catch (IllegalArgumentException 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; - } + + 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; + } catch (IllegalArgumentException 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/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java index 6d368e11..ee64a1b3 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java +++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java @@ -1,6 +1,6 @@ /** * 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 @@ -16,18 +16,20 @@ */ package se.leap.bitmaskclient; -import android.annotation.SuppressLint; +import android.annotation.*; import android.app.*; import android.content.*; -import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManager.*; import android.os.*; -import android.util.Log; +import android.util.*; import android.view.*; import android.widget.*; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.*; import org.json.*; + import java.net.*; +import java.util.*; import butterknife.*; import de.blinkt.openvpn.activities.*; @@ -36,11 +38,11 @@ import se.leap.bitmaskclient.eip.*; /** * The main user facing Activity of Bitmask Android, consisting of status, controls, * and access to preferences. - * + * * @author Sean Leonard <meanderingcode@aetherislands.net> * @author parmegv */ -public class Dashboard extends Activity implements SessionDialog.SessionDialogInterface, ProviderAPIResultReceiver.Receiver { +public class Dashboard extends Activity implements SessionDialog.SessionDialogInterface, ProviderAPIResultReceiver.Receiver, Observer { protected static final int CONFIGURE_LEAP = 0; protected static final int SWITCH_PROVIDER = 1; @@ -60,47 +62,65 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn @InjectView(R.id.providerName) TextView provider_name; + @InjectView(R.id.user_session_status) + TextView user_session_status_text_view; + @InjectView(R.id.user_session_status_progress) + ProgressBar user_session_status_progress_bar; EipFragment eip_fragment; private Provider provider; - private static boolean authed_eip; + private UserSessionStatus user_session_status; public ProviderAPIResultReceiver providerAPI_result_receiver; private boolean switching_provider; @Override protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - app = this; + super.onCreate(savedInstanceState); + + app = this; + user_session_status = UserSessionStatus.getInstance(); + user_session_status.addObserver(this); - PRNGFixes.apply(); + PRNGFixes.apply(); - preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); - fragment_manager = new FragmentManagerEnhanced(getFragmentManager()); - handleVersion(); + preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + fragment_manager = new FragmentManagerEnhanced(getFragmentManager()); + handleVersion(); - provider = getSavedProvider(savedInstanceState); + restoreProvider(savedInstanceState); if (provider == null || provider.getName().isEmpty()) - startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); - else - buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false)); + startActivityForResult(new Intent(this, ConfigurationWizard.class), CONFIGURE_LEAP); + else { + buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false)); + restoreSessionStatus(savedInstanceState); + } + } + + private void restoreProvider(Bundle savedInstanceState) { + if (savedInstanceState != null) { + if (savedInstanceState.containsKey(Provider.KEY)) + provider = savedInstanceState.getParcelable(Provider.KEY); + } + if (provider == null && preferences.getBoolean(Constants.PROVIDER_CONFIGURED, false)) + provider = getSavedProviderFromSharedPreferences(); + } + + private void restoreSessionStatus(Bundle savedInstanceState) { + if (savedInstanceState != null) + if (savedInstanceState.containsKey(UserSessionStatus.TAG)) { + UserSessionStatus.SessionStatus status = (UserSessionStatus.SessionStatus) savedInstanceState.getSerializable(UserSessionStatus.TAG); + user_session_status.updateStatus(status); + } } @Override protected void onSaveInstanceState(@NotNull Bundle outState) { - if(provider != null) + if (provider != null) outState.putParcelable(Provider.KEY, provider); - super.onSaveInstanceState(outState); - } - - private Provider getSavedProvider(Bundle savedInstanceState) { - Provider provider = null; - if(savedInstanceState != null) - provider = savedInstanceState.getParcelable(Provider.KEY); - else if(preferences.getBoolean(Constants.PROVIDER_CONFIGURED, false)) - provider = getSavedProviderFromSharedPreferences(); + if (user_session_status_text_view != null && user_session_status_text_view.getVisibility() == TextView.VISIBLE) + outState.putSerializable(UserSessionStatus.TAG, user_session_status.sessionStatus()); - return provider; + super.onSaveInstanceState(outState); } private Provider getSavedProviderFromSharedPreferences() { @@ -108,9 +128,7 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn try { provider = new Provider(new URL(preferences.getString(Provider.MAIN_URL, ""))); provider.define(new JSONObject(preferences.getString(Provider.KEY, ""))); - } catch (MalformedURLException e) { - e.printStackTrace(); - } catch (JSONException e) { + } catch (MalformedURLException | JSONException e) { e.printStackTrace(); } @@ -118,27 +136,27 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn } private void handleVersion() { - try { - int versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode; - int lastDetectedVersion = preferences.getInt(APP_VERSION, 0); - preferences.edit().putInt(APP_VERSION, versionCode).apply(); - - switch(versionCode) { - case 91: // 0.6.0 without Bug #5999 - case 101: // 0.8.0 - if(!preferences.getString(Constants.KEY, "").isEmpty()) - eip_fragment.updateEipService(); - break; - } - } catch (NameNotFoundException e) { - Log.d(TAG, "Handle version didn't find any " + getPackageName() + " package"); - } + try { + int versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode; + int lastDetectedVersion = preferences.getInt(APP_VERSION, 0); + preferences.edit().putInt(APP_VERSION, versionCode).apply(); + + switch (versionCode) { + case 91: // 0.6.0 without Bug #5999 + case 101: // 0.8.0 + if (!preferences.getString(Constants.KEY, "").isEmpty()) + eip_fragment.updateEipService(); + break; + } + } catch (NameNotFoundException e) { + Log.d(TAG, "Handle version didn't find any " + getPackageName() + " package"); + } } @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data){ - if ( requestCode == CONFIGURE_LEAP || requestCode == SWITCH_PROVIDER) { - if ( resultCode == RESULT_OK && data.hasExtra(Provider.KEY)) { + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == CONFIGURE_LEAP || requestCode == SWITCH_PROVIDER) { + if (resultCode == RESULT_OK && data.hasExtra(Provider.KEY)) { provider = data.getParcelableExtra(Provider.KEY); providerToPreferences(provider); @@ -148,14 +166,13 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn sessionDialog(Bundle.EMPTY); } - preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply(); - } else if (resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) { + } else if (resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) { finish(); - } else - configErrorDialog(); - } else if(requestCode == EIP.DISCONNECT) { - EipStatus.getInstance().setConnectedOrDisconnected(); - } + } else + configErrorDialog(); + } else if (requestCode == EIP.DISCONNECT) { + EipStatus.getInstance().setConnectedOrDisconnected(); + } } @SuppressLint("CommitPrefEdits") @@ -166,197 +183,237 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn } 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) { - preferences.edit().remove(Provider.KEY).remove(Constants.PROVIDER_CONFIGURED).apply(); - finish(); - } - }) - .show(); - } - + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getContext()); + 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(getContext(), ConfigurationWizard.class), CONFIGURE_LEAP); + } + }) + .setNegativeButton(getResources().getString(R.string.setup_error_close_button), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + preferences.edit().remove(Provider.KEY).remove(Constants.PROVIDER_CONFIGURED).apply(); + finish(); + } + }) + .show(); + } + /** * Inflates permanent UI elements of the View and contains logic for what * service dependent UI elements to include. */ private void buildDashboard(boolean hide_and_turn_on_eip) { - setContentView(R.layout.dashboard); + setContentView(R.layout.dashboard); ButterKnife.inject(this); - provider_name.setText(provider.getDomain()); - if ( provider.hasEIP()){ + provider_name.setText(provider.getDomain()); + if (provider.hasEIP()) { fragment_manager.removePreviousFragment(EipFragment.TAG); eip_fragment = new EipFragment(); - if (hide_and_turn_on_eip) { - preferences.edit().remove(Dashboard.START_ON_BOOT).apply(); - Bundle arguments = new Bundle(); - arguments.putBoolean(EipFragment.START_ON_BOOT, true); - if(eip_fragment != null) eip_fragment.setArguments(arguments); - } + if (hide_and_turn_on_eip) { + preferences.edit().remove(Dashboard.START_ON_BOOT).apply(); + Bundle arguments = new Bundle(); + arguments.putBoolean(EipFragment.START_ON_BOOT, true); + if (eip_fragment != null) eip_fragment.setArguments(arguments); + } fragment_manager.replace(R.id.servicesCollection, eip_fragment, EipFragment.TAG); - if (hide_and_turn_on_eip) { - onBackPressed(); - } - } + if (hide_and_turn_on_eip) { + onBackPressed(); + } + } + handleNewUserSessionStatus(user_session_status); } @Override public boolean onPrepareOptionsMenu(Menu menu) { - JSONObject provider_json; - try { - String provider_json_string = preferences.getString(Provider.KEY, ""); - if(!provider_json_string.isEmpty()) { - provider_json = new JSONObject(provider_json_string); - JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); - boolean authed_eip = !LeapSRPSession.getToken().isEmpty(); - boolean allow_registered_eip = service_description.getBoolean(Provider.ALLOW_REGISTRATION); - preferences.edit().putBoolean(Constants.ALLOWED_REGISTERED, allow_registered_eip).apply(); - - if(allow_registered_eip) { - if(authed_eip) { - menu.findItem(R.id.login_button).setVisible(false); - menu.findItem(R.id.logout_button).setVisible(true); - } else { - menu.findItem(R.id.login_button).setVisible(true); - menu.findItem(R.id.logout_button).setVisible(false); - } - menu.findItem(R.id.signup_button).setVisible(true); - } - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return true; + if (provider.allowsRegistration()) { + menu.findItem(R.id.signup_button).setVisible(true); + + boolean logged_in = User.loggedIn(); + menu.findItem(R.id.login_button).setVisible(!logged_in); + menu.findItem(R.id.logout_button).setVisible(logged_in); + } + return true; } @Override public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.client_dashboard, menu); - return true; + 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.log_window: - Intent startLW = new Intent(getAppContext(), LogWindow.class); - startLW.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivity(startLW); - return true; - case R.id.switch_provider: - switching_provider = true; - if (preferences.getBoolean(Constants.AUTHED_EIP, false)) logOut(); - else switchProvider(); - return true; - case R.id.login_button: - sessionDialog(Bundle.EMPTY); - return true; - case R.id.logout_button: - logOut(); - return true; - case R.id.signup_button: - sessionDialog(Bundle.EMPTY); - return true; - default: - return super.onOptionsItemSelected(item); - } + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.about_leap: + showAbout(); + return true; + case R.id.log_window: + showLog(); + return true; + case R.id.switch_provider: + switching_provider = true; + if (LeapSRPSession.loggedIn()) logOut(); + else switchProvider(); + return true; + case R.id.login_button: + sessionDialog(Bundle.EMPTY); + return true; + case R.id.logout_button: + logOut(); + return true; + case R.id.signup_button: + sessionDialog(Bundle.EMPTY); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + public void showAbout() { + Intent intent = new Intent(this, AboutActivity.class); + startActivity(intent); + } + + public void showLog() { + Intent startLW = new Intent(getContext(), LogWindow.class); + startActivity(startLW); } @Override public void signUp(String username, String password) { - Bundle parameters = bundleParameters(username, password); - providerApiCommand(parameters, R.string.signingup_message, ProviderAPI.SRP_REGISTER); + User.setUserName(username); + Bundle parameters = bundlePassword(password); + providerApiCommand(parameters, 0, ProviderAPI.SIGN_UP); } @Override public void logIn(String username, String password) { - Bundle parameters = bundleParameters(username, password); - providerApiCommand(parameters, R.string.authenticating_message, ProviderAPI.SRP_AUTH); + User.setUserName(username); + Bundle parameters = bundlePassword(password); + providerApiCommand(parameters, 0, ProviderAPI.LOG_IN); } - + public void logOut() { - providerApiCommand(Bundle.EMPTY, R.string.logout_message, ProviderAPI.LOG_OUT); + providerApiCommand(Bundle.EMPTY, 0, ProviderAPI.LOG_OUT); + } + + @Override + public void update(Observable observable, Object data) { + if (observable instanceof UserSessionStatus) { + UserSessionStatus status = (UserSessionStatus) observable; + handleNewUserSessionStatus(status); + } + } + + private void handleNewUserSessionStatus(UserSessionStatus status) { + user_session_status = status; + if (provider.allowsRegistration()) { + if (user_session_status.inProgress()) + showUserSessionProgressBar(); + else + hideUserSessionProgressBar(); + changeSessionStatusMessage(user_session_status.toString()); + invalidateOptionsMenu(); + } + } + + private void changeSessionStatusMessage(final String message) { + runOnUiThread(new Runnable() { + @Override + public void run() { + user_session_status_text_view.setText(message); + } + }); + } + + private void showUserSessionProgressBar() { + runOnUiThread(new Runnable() { + @Override + public void run() { + user_session_status_progress_bar.setVisibility(ProgressBar.VISIBLE); + } + }); + } + + private void hideUserSessionProgressBar() { + runOnUiThread(new Runnable() { + @Override + public void run() { + user_session_status_progress_bar.setVisibility(ProgressBar.GONE); + } + }); } protected void downloadVpnCertificate() { - boolean is_authenticated = !LeapSRPSession.getToken().isEmpty(); + boolean is_authenticated = LeapSRPSession.loggedIn(); boolean allowed_anon = preferences.getBoolean(Constants.ALLOWED_ANON, false); - if(allowed_anon || is_authenticated) + if (allowed_anon || is_authenticated) providerApiCommand(Bundle.EMPTY, R.string.downloading_certificate_message, ProviderAPI.DOWNLOAD_CERTIFICATE); else sessionDialog(Bundle.EMPTY); } - private Bundle bundleParameters(String username, String password) { + private Bundle bundlePassword(String password) { Bundle parameters = new Bundle(); - if(!username.isEmpty()) - parameters.putString(SessionDialog.USERNAME, username); - if(!password.isEmpty()) - parameters.putString(SessionDialog.PASSWORD, password); - return parameters; + if (!password.isEmpty()) + parameters.putString(SessionDialog.PASSWORD, password); + return parameters; } protected void providerApiCommand(Bundle parameters, int progressbar_message_resId, String providerApi_action) { - if(eip_fragment != null && progressbar_message_resId != 0) { + if (eip_fragment != null && progressbar_message_resId != 0) { eip_fragment.progress_bar.setVisibility(ProgressBar.VISIBLE); setStatusMessage(progressbar_message_resId); } - - Intent command = prepareProviderAPICommand(parameters, providerApi_action); - startService(command); + + Intent command = prepareProviderAPICommand(parameters, providerApi_action); + startService(command); } private Intent prepareProviderAPICommand(Bundle parameters, String action) { - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - - Intent command = new Intent(this, ProviderAPI.class); - - command.putExtra(ProviderAPI.PARAMETERS, parameters); - command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - command.setAction(action); - return command; + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + + Intent command = new Intent(this, ProviderAPI.class); + + command.putExtra(ProviderAPI.PARAMETERS, parameters); + command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); + command.setAction(action); + return command; } public void cancelLoginOrSignup() { - EipStatus.getInstance().setConnectedOrDisconnected(); + EipStatus.getInstance().setConnectedOrDisconnected(); } - + public void sessionDialog(Bundle resultData) { - - FragmentTransaction transaction = fragment_manager.removePreviousFragment(SessionDialog.TAG); - DialogFragment newFragment = new SessionDialog(); - if(resultData != null && !resultData.isEmpty()) { - newFragment.setArguments(resultData); - } - newFragment.show(transaction, SessionDialog.TAG); + FragmentTransaction transaction = fragment_manager.removePreviousFragment(SessionDialog.TAG); + + DialogFragment newFragment = new SessionDialog(); + if (provider.getName().equalsIgnoreCase("riseup")) { + resultData = resultData == Bundle.EMPTY ? new Bundle() : resultData; + resultData.putBoolean(SessionDialog.ERRORS.RISEUP_WARNING.toString(), true); + } + if (resultData != null && !resultData.isEmpty()) { + newFragment.setArguments(resultData); + } + newFragment.show(transaction, SessionDialog.TAG); } private void switchProvider() { - if (provider.hasEIP()) eip_fragment.askToStopEIP(); - + if (provider.hasEIP()) eip_fragment.stopEipIfPossible(); + preferences.edit().clear().apply(); switching_provider = false; startActivityForResult(new Intent(this, ConfigurationWizard.class), SWITCH_PROVIDER); @@ -364,113 +421,43 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn @Override public void onReceiveResult(int resultCode, Bundle resultData) { - Log.d(TAG, "onReceiveResult"); - if(resultCode == ProviderAPI.SUCCESSFUL_SIGNUP) { - String username = resultData.getString(SessionDialog.USERNAME); - String password = resultData.getString(SessionDialog.PASSWORD); - logIn(username, password); - } else if(resultCode == ProviderAPI.FAILED_SIGNUP) { - updateViewHidingProgressBar(resultCode); - sessionDialog(resultData); - } else if(resultCode == ProviderAPI.SUCCESSFUL_LOGIN) { - authed_eip = true; - preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply(); - - updateViewHidingProgressBar(resultCode); - downloadVpnCertificate(); - } else if(resultCode == ProviderAPI.FAILED_LOGIN) { - updateViewHidingProgressBar(resultCode); - sessionDialog(resultData); - } else if(resultCode == ProviderAPI.SUCCESSFUL_LOGOUT) { - authed_eip = false; - preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply(); - - updateViewHidingProgressBar(resultCode); - if(switching_provider) switchProvider(); - } else if(resultCode == ProviderAPI.LOGOUT_FAILED) { - updateViewHidingProgressBar(resultCode); - setResult(RESULT_CANCELED); - } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { - updateViewHidingProgressBar(resultCode); - eip_fragment.updateEipService(); - setResult(RESULT_OK); - } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { - updateViewHidingProgressBar(resultCode); - setResult(RESULT_CANCELED); - } - else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE) { - eip_fragment.updateEipService(); - setResult(RESULT_OK); - } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE) { - setResult(RESULT_CANCELED); - } - } - - private void updateViewHidingProgressBar(int resultCode) { - changeStatusMessage(resultCode); - hideProgressBar(); - invalidateOptionsMenu(); - } - - private void changeStatusMessage(final int previous_result_code) { - ResultReceiver status_receiver = new ResultReceiver(new Handler()){ - protected void onReceiveResult(int resultCode, Bundle resultData){ - super.onReceiveResult(resultCode, resultData); - String request = resultData.getString(Constants.REQUEST_TAG); - if (request.equalsIgnoreCase(Constants.ACTION_IS_EIP_RUNNING)){ - if (resultCode == Activity.RESULT_OK){ - switch(previous_result_code){ - case ProviderAPI.SUCCESSFUL_LOGIN: setStatusMessage(R.string.succesful_authentication_message); break; - case ProviderAPI.FAILED_LOGIN: setStatusMessage(R.string.authentication_failed_message); break; - case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: setStatusMessage(R.string.authed_secured_status); break; - case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: setStatusMessage(R.string.incorrectly_downloaded_certificate_message); break; - case ProviderAPI.SUCCESSFUL_LOGOUT: setStatusMessage(R.string.logged_out_message); break; - case ProviderAPI.LOGOUT_FAILED: setStatusMessage(R.string.log_out_failed_message); break; - - } - } - else if(resultCode == Activity.RESULT_CANCELED){ - switch(previous_result_code){ - case ProviderAPI.SUCCESSFUL_LOGIN: setStatusMessage(R.string.succesful_authentication_message); break; - case ProviderAPI.FAILED_LOGIN: setStatusMessage(R.string.authentication_failed_message); break; - case ProviderAPI.FAILED_SIGNUP: setStatusMessage(R.string.registration_failed_message); break; - case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: break; - case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: setStatusMessage(R.string.incorrectly_downloaded_certificate_message); break; - case ProviderAPI.SUCCESSFUL_LOGOUT: setStatusMessage(R.string.logged_out_message); break; - case ProviderAPI.LOGOUT_FAILED: setStatusMessage(R.string.log_out_failed_message); break; - } - } - } - - } - }; - eipIsRunning(status_receiver); + if (resultCode == ProviderAPI.SUCCESSFUL_SIGNUP) { + String username = resultData.getString(SessionDialog.USERNAME); + String password = resultData.getString(SessionDialog.PASSWORD); + logIn(username, password); + } else if (resultCode == ProviderAPI.FAILED_SIGNUP) { + sessionDialog(resultData); + } else if (resultCode == ProviderAPI.SUCCESSFUL_LOGIN) { + downloadVpnCertificate(); + } else if (resultCode == ProviderAPI.FAILED_LOGIN) { + sessionDialog(resultData); + } else if (resultCode == ProviderAPI.SUCCESSFUL_LOGOUT) { + if (switching_provider) switchProvider(); + } else if (resultCode == ProviderAPI.LOGOUT_FAILED) { + setResult(RESULT_CANCELED); + } else if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { + eip_fragment.updateEipService(); + eip_fragment.handleNewVpnCertificate(); + setResult(RESULT_OK); + } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { + setResult(RESULT_CANCELED); + } else if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE) { + eip_fragment.updateEipService(); + setResult(RESULT_OK); + } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE) { + setResult(RESULT_CANCELED); + } } private void setStatusMessage(int string_resId) { - if(eip_fragment != null && eip_fragment.status_message != null) - eip_fragment.status_message.setText(string_resId); + if (eip_fragment != null && eip_fragment.status_message != null) + eip_fragment.status_message.setText(string_resId); } - 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 intent = new Intent(this, EIP.class); - intent.setAction(Constants.ACTION_IS_EIP_RUNNING); - intent.putExtra(Constants.RECEIVER_TAG, eip_receiver); - startService(intent); + public static Context getContext() { + return app; } - private void hideProgressBar() { - if(eip_fragment != null) { - eip_fragment.progress_bar.setProgress(0); - eip_fragment.progress_bar.setVisibility(ProgressBar.GONE); - } - } - - public static Context getAppContext() { - return app; - } - @Override public void startActivityForResult(Intent intent, int requestCode) { intent.putExtra(Dashboard.REQUEST_CODE, requestCode); diff --git a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java index a44253c6..da32dbd4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java @@ -1,6 +1,6 @@ /** * 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 @@ -16,76 +16,74 @@ */ package se.leap.bitmaskclient; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.os.Bundle; +import android.app.*; +import android.content.*; +import android.os.*; /** * Implements a dialog to show why a download failed. - * - * @author parmegv * + * @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; - } + 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()); - @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(); + } + }); - 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(); + } - // Create the AlertDialog object and return it - return builder.create(); - } + public interface DownloadFailedDialogInterface { + public void retrySetUpProvider(); - public interface DownloadFailedDialogInterface { - public void retrySetUpProvider(); - public void cancelSettingUpProvider(); - } + public void cancelSettingUpProvider(); + } - DownloadFailedDialogInterface interface_with_ConfigurationWizard; + 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 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(); - } + @Override + public void onCancel(DialogInterface dialog) { + interface_with_ConfigurationWizard.cancelSettingUpProvider(); + dialog.dismiss(); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java index 588b137b..02eedd77 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java @@ -1,35 +1,38 @@ +/** + * Copyright (c) 2013 LEAP Encryption Access Project and contributers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package se.leap.bitmaskclient; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.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.View; -import android.view.ViewGroup; -import android.widget.ProgressBar; -import android.widget.Switch; -import android.widget.TextView; - -import java.util.Observable; -import java.util.Observer; - -import butterknife.ButterKnife; -import butterknife.InjectView; -import butterknife.OnCheckedChanged; -import de.blinkt.openvpn.activities.DisconnectVPN; -import se.leap.bitmaskclient.eip.Constants; -import se.leap.bitmaskclient.eip.EIP; -import se.leap.bitmaskclient.eip.EipStatus; -import se.leap.bitmaskclient.eip.VoidVpnService; +import android.app.*; +import android.content.*; +import android.os.*; +import android.util.*; +import android.view.*; +import android.widget.*; + +import org.jetbrains.annotations.*; + +import java.util.*; + +import butterknife.*; +import de.blinkt.openvpn.activities.*; +import se.leap.bitmaskclient.eip.*; public class EipFragment extends Fragment implements Observer { - + public static String TAG = EipFragment.class.getSimpleName(); protected static final String IS_PENDING = TAG + ".is_pending"; @@ -50,316 +53,347 @@ public class EipFragment extends Fragment implements Observer { private boolean is_starting_to_connect; private boolean wants_to_connect; - @Override public void onAttach(Activity activity) { - super.onAttach(activity); + super.onAttach(activity); dashboard = (Dashboard) activity; dashboard.providerApiCommand(Bundle.EMPTY, 0, ProviderAPI.DOWNLOAD_EIP_SERVICE); } - + @Override public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - eip_status = EipStatus.getInstance(); - eip_status.addObserver(this); - mEIPReceiver = new EIPReceiver(new Handler()); + super.onCreate(savedInstanceState); + eip_status = EipStatus.getInstance(); + eip_status.addObserver(this); + mEIPReceiver = new EIPReceiver(new Handler()); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.eip_service_fragment, container, false); + View view = inflater.inflate(R.layout.eip_service_fragment, container, false); ButterKnife.inject(this, view); - if (eip_status.isConnecting()) - eip_switch.setVisibility(View.VISIBLE); - - Log.d(TAG, "onCreateView, eip_switch is checked? " + eip_switch.isChecked()); + if (eip_status.isConnecting()) + eip_switch.setVisibility(View.VISIBLE); Bundle arguments = getArguments(); - if(arguments != null && arguments.containsKey(START_ON_BOOT) && arguments.getBoolean(START_ON_BOOT)) - startEipFromScratch(); + if (arguments != null && arguments.containsKey(START_ON_BOOT) && arguments.getBoolean(START_ON_BOOT)) + startEipFromScratch(); + if (savedInstanceState != null) restoreState(savedInstanceState); + + return view; + } - if (savedInstanceState != null) { + private void restoreState(@NotNull Bundle savedInstanceState) { + if (savedInstanceState.getBoolean(IS_PENDING)) + eip_status.setConnecting(); + else if (savedInstanceState.getBoolean(IS_CONNECTED)) + eip_status.setConnectedOrDisconnected(); + else status_message.setText(savedInstanceState.getString(STATUS_MESSAGE)); - if(savedInstanceState.getBoolean(IS_PENDING)) - eip_status.setConnecting(); - else if(savedInstanceState.getBoolean(IS_CONNECTED)) { - eip_status.setConnectedOrDisconnected(); - } - } - return view; } @Override public void onResume() { - super.onResume(); - eipCommand(Constants.ACTION_CHECK_CERT_VALIDITY); - handleNewState(eip_status); + super.onResume(); + eipCommand(Constants.ACTION_CHECK_CERT_VALIDITY); + handleNewState(eip_status); } - + @Override public void onSaveInstanceState(Bundle outState) { - outState.putBoolean(IS_PENDING, eip_status.isConnecting()); - outState.putBoolean(IS_CONNECTED, eip_status.isConnected()); - Log.d(TAG, "status message onSaveInstanceState = " + status_message.getText().toString()); - outState.putString(STATUS_MESSAGE, status_message.getText().toString()); - super.onSaveInstanceState(outState); + outState.putBoolean(IS_PENDING, eip_status.isConnecting()); + outState.putBoolean(IS_CONNECTED, eip_status.isConnected()); + outState.putString(STATUS_MESSAGE, status_message.getText().toString()); + super.onSaveInstanceState(outState); } protected void saveStatus() { - boolean is_on = eip_switch.isChecked(); - Log.d(TAG, "saveStatus: is_on = " + is_on); - Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, is_on).commit(); + boolean is_on = eip_switch.isChecked(); + Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, is_on).commit(); + } + + void handleNewVpnCertificate() { + handleSwitch(!eip_switch.isEnabled()); } @OnCheckedChanged(R.id.eipSwitch) void handleSwitch(boolean isChecked) { - if(isChecked) - handleSwitchOn(); - else - handleSwitchOff(); - - saveStatus(); + if (isChecked) + handleSwitchOn(); + else + handleSwitchOff(); + + saveStatus(); } private void handleSwitchOn() { - if(canStartEIP()) - startEipFromScratch(); - else if(canLogInToStartEIP()) { - wants_to_connect = true; - Bundle bundle = new Bundle(); - bundle.putBoolean(IS_PENDING, true); - dashboard.sessionDialog(bundle); - } - } - + if (canStartEIP()) + startEipFromScratch(); + else if (canLogInToStartEIP()) { + wants_to_connect = true; + Bundle bundle = new Bundle(); + bundle.putBoolean(IS_PENDING, true); + dashboard.sessionDialog(bundle); + } + } + private boolean canStartEIP() { - boolean certificateExists = !Dashboard.preferences.getString(Constants.CERTIFICATE, "").isEmpty(); - boolean isAllowedAnon = Dashboard.preferences.getBoolean(Constants.ALLOWED_ANON, false); - return (isAllowedAnon || certificateExists) && !eip_status.isConnected() && !eip_status.isConnecting(); + boolean certificateExists = !Dashboard.preferences.getString(Constants.CERTIFICATE, "").isEmpty(); + boolean isAllowedAnon = Dashboard.preferences.getBoolean(Constants.ALLOWED_ANON, false); + return (isAllowedAnon || certificateExists) && !eip_status.isConnected() && !eip_status.isConnecting(); } - + private boolean canLogInToStartEIP() { - boolean isAllowedRegistered = Dashboard.preferences.getBoolean(Constants.ALLOWED_REGISTERED, false); - boolean isLoggedIn = !LeapSRPSession.getToken().isEmpty(); - Log.d(TAG, "Allow registered? " + isAllowedRegistered); - Log.d(TAG, "Is logged in? " + isLoggedIn); - return isAllowedRegistered && !isLoggedIn && !eip_status.isConnecting() && !eip_status.isConnected(); + boolean isAllowedRegistered = Dashboard.preferences.getBoolean(Constants.ALLOWED_REGISTERED, false); + boolean isLoggedIn = !LeapSRPSession.getToken().isEmpty(); + return isAllowedRegistered && !isLoggedIn && !eip_status.isConnecting() && !eip_status.isConnected(); } private void handleSwitchOff() { - if(eip_status.isConnecting()) { - askPendingStartCancellation(); - } else if(eip_status.isConnected()) { - askToStopEIP(); - } - } - - private void askPendingStartCancellation() { - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(dashboard); - alertBuilder.setTitle(dashboard.getString(R.string.eip_cancel_connect_title)) - .setMessage(dashboard.getString(R.string.eip_cancel_connect_text)) - .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - askToStopEIP(); - } - }) - .setNegativeButton(dashboard.getString(R.string.no), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - eip_switch.setChecked(true); - } - }) - .show(); + if (eip_status.isConnecting()) { + askPendingStartCancellation(); + } else if (eip_status.isConnected()) { + askToStopEIP(); + } else + setDisconnectedUI(); + } + + private void askPendingStartCancellation() { + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(dashboard); + alertBuilder.setTitle(dashboard.getString(R.string.eip_cancel_connect_title)) + .setMessage(dashboard.getString(R.string.eip_cancel_connect_text)) + .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + askToStopEIP(); + } + }) + .setNegativeButton(dashboard.getString(R.string.no), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + eip_switch.setChecked(true); + } + }) + .show(); } public void startEipFromScratch() { wants_to_connect = false; is_starting_to_connect = true; progress_bar.setVisibility(View.VISIBLE); - eip_switch.setVisibility(View.VISIBLE); - String status = dashboard.getString(R.string.eip_status_start_pending); - status_message.setText(status); - - if(!eip_switch.isChecked()) { - eip_switch.setChecked(true); - } + eip_switch.setVisibility(View.VISIBLE); + String status = dashboard.getString(R.string.eip_status_start_pending); + status_message.setText(status); + + if (!eip_switch.isChecked()) { + eip_switch.setChecked(true); + } saveStatus(); - eipCommand(Constants.ACTION_START_EIP); + eipCommand(Constants.ACTION_START_EIP); } - private void stopEIP() { - if(eip_status.isConnecting()) - VoidVpnService.stop(); - Intent disconnect_vpn = new Intent(dashboard, DisconnectVPN.class); - dashboard.startActivityForResult(disconnect_vpn, EIP.DISCONNECT); - eip_status.setDisconnecting(); + private void stop() { + if (eip_status.isConnecting()) + VoidVpnService.stop(); + disconnect(); } - protected void askToStopEIP() { + private void disconnect() { + Intent disconnect_vpn = new Intent(dashboard, DisconnectVPN.class); + dashboard.startActivityForResult(disconnect_vpn, EIP.DISCONNECT); + eip_status.setDisconnecting(); + } + + protected void stopEipIfPossible() { + hideProgressBar(); - String status = dashboard.getString(R.string.eip_state_not_connected); - status_message.setText(status); + String message = dashboard.getString(R.string.eip_state_not_connected); + status_message.setText(message); - eipCommand(Constants.ACTION_STOP_EIP); + eipCommand(Constants.ACTION_STOP_EIP); + } + + private void askToStopEIP() { + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(dashboard); + alertBuilder.setTitle(dashboard.getString(R.string.eip_cancel_connect_title)) + .setMessage(dashboard.getString(R.string.eip_warning_browser_inconsistency)) + .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + stopEipIfPossible(); + } + }) + .setNegativeButton(dashboard.getString(R.string.no), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + eip_switch.setChecked(true); + } + }) + .show(); } protected void updateEipService() { eipCommand(Constants.ACTION_UPDATE_EIP_SERVICE); } - + /** * Send a command to EIP - * - * @param action A valid String constant from EIP class representing an Intent - * filter for the EIP class + * + * @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 vpn_intent = new Intent(dashboard.getApplicationContext(), EIP.class); - vpn_intent.setAction(action); - vpn_intent.putExtra(Constants.RECEIVER_TAG, mEIPReceiver); - dashboard.startService(vpn_intent); - } - + private void eipCommand(String action) { + // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? + Intent vpn_intent = new Intent(dashboard.getApplicationContext(), EIP.class); + vpn_intent.setAction(action); + vpn_intent.putExtra(Constants.RECEIVER_TAG, mEIPReceiver); + dashboard.startService(vpn_intent); + } + @Override - public void update (Observable observable, Object data) { - if(observable instanceof EipStatus) { - eip_status = (EipStatus) observable; - final EipStatus eip_status = (EipStatus) observable; - dashboard.runOnUiThread(new Runnable() { - @Override - public void run() { - handleNewState(eip_status); - } - }); - } + public void update(Observable observable, Object data) { + if (observable instanceof EipStatus) { + eip_status = (EipStatus) observable; + final EipStatus eip_status = (EipStatus) observable; + dashboard.runOnUiThread(new Runnable() { + @Override + public void run() { + handleNewState(eip_status); + } + }); + } } private void handleNewState(EipStatus eip_status) { - Log.d(TAG, "handleNewState: " + eip_status.toString()); - if(eip_status.wantsToDisconnect()) - setDisconnectedUI(); - else if(eip_status.isConnecting() || is_starting_to_connect) - setInProgressUI(eip_status); - else if (eip_status.isConnected()) - setConnectedUI(); - else if (eip_status.isDisconnected() && !eip_status.isConnecting()) - setDisconnectedUI(); + if (eip_status.wantsToDisconnect()) + setDisconnectedUI(); + else if (eip_status.isConnecting() || is_starting_to_connect) + setInProgressUI(eip_status); + else if (eip_status.isConnected()) + setConnectedUI(); + else if (eip_status.isDisconnected() && !eip_status.isConnecting()) + setDisconnectedUI(); } private void setConnectedUI() { - hideProgressBar(); - Log.d(TAG, "setConnectedUi? " + eip_status.isConnected()); - adjustSwitch(); - is_starting_to_connect = false; - status_message.setText(dashboard.getString(R.string.eip_state_connected)); + hideProgressBar(); + adjustSwitch(); + is_starting_to_connect = false; + status_message.setText(dashboard.getString(R.string.eip_state_connected)); } - private void setDisconnectedUI(){ - hideProgressBar(); - adjustSwitch(); - status_message.setText(dashboard.getString(R.string.eip_state_not_connected)); + private void setDisconnectedUI() { + hideProgressBar(); + adjustSwitch(); + if (eip_status.errorInLast(5, dashboard.getApplicationContext()) + && !status_message.getText().toString().equalsIgnoreCase(dashboard.getString(R.string.eip_state_not_connected))) { + dashboard.showLog(); + VoidVpnService.stop(); + } + status_message.setText(dashboard.getString(R.string.eip_state_not_connected)); } private void adjustSwitch() { - if(eip_status.isConnected() || eip_status.isConnecting() || is_starting_to_connect) { - Log.d(TAG, "adjustSwitch, isConnected || isConnecting, is checked"); - if(!eip_switch.isChecked()) { - eip_switch.setChecked(true); - } - } else { - Log.d(TAG, "adjustSwitch, !isConnected && !isConnecting? " + eip_status.toString()); + if (eip_status.isConnected() || eip_status.isConnecting() || is_starting_to_connect) { + if (!eip_switch.isChecked()) { + eip_switch.setChecked(true); + } + } else { - if(eip_switch.isChecked()) { - eip_switch.setChecked(false); - } - } + if (eip_switch.isChecked()) { + eip_switch.setChecked(false); + } + } } private void setInProgressUI(EipStatus eip_status) { - int localizedResId = eip_status.getLocalizedResId(); - String logmessage = eip_status.getLogMessage(); - String prefix = dashboard.getString(localizedResId); + int localizedResId = eip_status.getLocalizedResId(); + String logmessage = eip_status.getLogMessage(); + String prefix = dashboard.getString(localizedResId); - status_message.setText(prefix + " " + logmessage); + showProgressBar(); + status_message.setText(prefix + " " + logmessage); is_starting_to_connect = false; - adjustSwitch(); + adjustSwitch(); } private void updatingCertificateUI() { - progress_bar.setVisibility(View.VISIBLE); + showProgressBar(); status_message.setText(getString(R.string.updating_certificate_message)); } + private void showProgressBar() { + if (progress_bar != null) + progress_bar.setVisibility(View.VISIBLE); + } + private void hideProgressBar() { - if(progress_bar != null) - progress_bar.setVisibility(View.GONE); + if (progress_bar != null) + progress_bar.setVisibility(View.GONE); } 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(Constants.REQUEST_TAG); - - if (request.equals(Constants.ACTION_START_EIP)) { - switch (resultCode){ - case Activity.RESULT_OK: - break; - case Activity.RESULT_CANCELED: - - break; - } - } else if (request.equals(Constants.ACTION_STOP_EIP)) { - switch (resultCode){ - case Activity.RESULT_OK: - stopEIP(); - break; - case Activity.RESULT_CANCELED: - break; - } - } else if (request.equals(Constants.EIP_NOTIFICATION)) { - switch (resultCode){ - case Activity.RESULT_OK: - break; - case Activity.RESULT_CANCELED: - break; - } - } else if (request.equals(Constants.ACTION_CHECK_CERT_VALIDITY)) { - switch (resultCode) { - case Activity.RESULT_OK: - break; - case Activity.RESULT_CANCELED: - updatingCertificateUI(); - dashboard.downloadVpnCertificate(); - break; - } - } else if (request.equals(Constants.ACTION_UPDATE_EIP_SERVICE)) { - switch (resultCode) { - case Activity.RESULT_OK: - if(wants_to_connect) - startEipFromScratch(); - break; - case Activity.RESULT_CANCELED: - handleNewState(eip_status); - break; + protected EIPReceiver(Handler handler) { + super(handler); + } + + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + super.onReceiveResult(resultCode, resultData); + + String request = resultData.getString(Constants.REQUEST_TAG); + + if (request.equals(Constants.ACTION_START_EIP)) { + switch (resultCode) { + case Activity.RESULT_OK: + break; + case Activity.RESULT_CANCELED: + + break; + } + } else if (request.equals(Constants.ACTION_STOP_EIP)) { + switch (resultCode) { + case Activity.RESULT_OK: + stop(); + break; + case Activity.RESULT_CANCELED: + break; + } + } else if (request.equals(Constants.EIP_NOTIFICATION)) { + switch (resultCode) { + case Activity.RESULT_OK: + break; + case Activity.RESULT_CANCELED: + break; + } + } else if (request.equals(Constants.ACTION_CHECK_CERT_VALIDITY)) { + switch (resultCode) { + case Activity.RESULT_OK: + break; + case Activity.RESULT_CANCELED: + updatingCertificateUI(); + dashboard.downloadVpnCertificate(); + break; + } + } else if (request.equals(Constants.ACTION_UPDATE_EIP_SERVICE)) { + switch (resultCode) { + case Activity.RESULT_OK: + if (wants_to_connect) + startEipFromScratch(); + break; + case Activity.RESULT_CANCELED: + handleNewState(eip_status); + break; + } } } - } } public static EIPReceiver getReceiver() { - return mEIPReceiver; + return mEIPReceiver; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/FragmentManagerEnhanced.java b/app/src/main/java/se/leap/bitmaskclient/FragmentManagerEnhanced.java index 49af9274..8ba7fa34 100644 --- a/app/src/main/java/se/leap/bitmaskclient/FragmentManagerEnhanced.java +++ b/app/src/main/java/se/leap/bitmaskclient/FragmentManagerEnhanced.java @@ -1,6 +1,6 @@ /** * 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 @@ -16,33 +16,31 @@ */ package se.leap.bitmaskclient; -import android.app.Fragment; -import android.app.FragmentManager; -import android.app.FragmentTransaction; +import android.app.*; public class FragmentManagerEnhanced { private FragmentManager generic_fragment_manager; - + public FragmentManagerEnhanced(FragmentManager generic_fragment_manager) { - this.generic_fragment_manager = generic_fragment_manager; + this.generic_fragment_manager = generic_fragment_manager; } - + public FragmentTransaction removePreviousFragment(String tag) { - FragmentTransaction transaction = generic_fragment_manager.beginTransaction(); - Fragment previous_fragment = generic_fragment_manager.findFragmentByTag(tag); - if (previous_fragment != null) { - transaction.remove(previous_fragment); - } - transaction.addToBackStack(null); - - return transaction; + FragmentTransaction transaction = generic_fragment_manager.beginTransaction(); + Fragment previous_fragment = generic_fragment_manager.findFragmentByTag(tag); + if (previous_fragment != null) { + transaction.remove(previous_fragment); + } + transaction.addToBackStack(null); + + return transaction; } public void replace(int containerViewId, Fragment fragment, String tag) { - FragmentTransaction transaction = generic_fragment_manager.beginTransaction(); - - transaction.replace(containerViewId, fragment, tag).commit(); + FragmentTransaction transaction = generic_fragment_manager.beginTransaction(); + + transaction.replace(containerViewId, fragment, tag).commit(); } public FragmentTransaction beginTransaction() { @@ -50,6 +48,6 @@ public class FragmentManagerEnhanced { } public Fragment findFragmentByTag(String tag) { - return generic_fragment_manager.findFragmentByTag(tag); + return generic_fragment_manager.findFragmentByTag(tag); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java index 989dc395..b961350e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java +++ b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java @@ -1,6 +1,6 @@ /** * 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 @@ -14,338 +14,348 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - package se.leap.bitmaskclient; +package se.leap.bitmaskclient; -import org.jboss.security.srp.SRPParameters; +import org.jboss.security.srp.*; -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 java.io.*; +import java.math.*; +import java.security.*; +import java.util.*; /** * Implements all SRP algorithm logic. - * + * <p/> * It's derived from JBoss implementation, with adjustments to make it work with LEAP platform. - * - * @author parmegv * + * @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"; - final public static String TAG= "Leap SRP session class tag"; - - 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) - { - this(username, password, 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, byte[] abytes) { - - params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), ConfigHelper.G.toByteArray(), BigInteger.ZERO.toByteArray(), "SHA-256"); - this.g = new BigInteger(1, params.g); - N_bytes = ConfigHelper.trim(params.N); - this.N = new BigInteger(1, N_bytes); - 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 ) + + 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"; + final public static String TAG = "Leap SRP session class tag"; + + private User user; + 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) { + this(username, password, 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, byte[] abytes) { + + params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), ConfigHelper.G.toByteArray(), BigInteger.ZERO.toByteArray(), "SHA-256"); + this.g = new BigInteger(1, params.g); + N_bytes = ConfigHelper.trim(params.N); + this.N = new BigInteger(1, N_bytes); + 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; - } + 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; + } public byte[] calculateNewSalt() { - try { - BigInteger salt = new BigInteger(64, SecureRandom.getInstance("SHA1PRNG")); - return ConfigHelper.trim(salt.toByteArray()); - } catch(NoSuchAlgorithmException e) { - e.printStackTrace(); - } - return null; + try { + BigInteger salt = new BigInteger(64, SecureRandom.getInstance("SHA1PRNG")); + return ConfigHelper.trim(salt.toByteArray()); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return null; } - /** - * Calculates the parameter V of the SRP-6a algorithm. - * @return the value of V - */ + + /** + * Calculates the parameter V of the SRP-6a algorithm. + * + * @return the value of V + */ public BigInteger calculateV(String username, String password, byte[] salt) { - byte[] x_bytes = calculatePasswordHash(username, password, ConfigHelper.trim(salt)); - x = new BigInteger(1, x_bytes); - BigInteger v = 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) { + byte[] x_bytes = calculatePasswordHash(username, password, ConfigHelper.trim(salt)); + x = new BigInteger(1, x_bytes); + BigInteger v = 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 - */ + 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) { - // Calculate x = H(s | H(U | ':' | password)) - byte[] M1 = null; - if(new BigInteger(1, Bbytes).mod(new BigInteger(1, N_bytes)) != BigInteger.ZERO) { - this.v = calculateV(username, password, salt_bytes); - // 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) - MessageDigest sessionDigest = newDigest(); - 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); - String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; - BigInteger k = new BigInteger(k_string, 16); - BigInteger B_minus_v = B.subtract(k.multiply(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; - } + // Calculate x = H(s | H(U | ':' | password)) + byte[] M1 = null; + if (new BigInteger(1, Bbytes).mod(new BigInteger(1, N_bytes)) != BigInteger.ZERO) { + this.v = calculateV(username, password, salt_bytes); + // 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) + MessageDigest sessionDigest = newDigest(); + 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); + String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; + BigInteger k = new BigInteger(k_string, 16); + BigInteger B_minus_v = B.subtract(k.multiply(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; + } + + protected static boolean loggedIn() { + return !token.isEmpty(); + } + + /** + * @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; + } public byte[] getK() { - return K; + return K; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java b/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java index 96b87085..9171e816 100644 --- a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java +++ b/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java @@ -1,31 +1,25 @@ package se.leap.bitmaskclient; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.util.Log; +import android.content.*; -import se.leap.bitmaskclient.eip.Constants; +import se.leap.bitmaskclient.eip.*; public class OnBootReceiver extends BroadcastReceiver { SharedPreferences preferences; - + // Debug: am broadcast -a android.intent.action.BOOT_COMPLETED @Override public void onReceive(Context context, Intent intent) { - preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Context.MODE_PRIVATE); - boolean provider_configured = !preferences.getString(Provider.KEY, "").isEmpty(); - boolean start_on_boot = preferences.getBoolean(Dashboard.START_ON_BOOT, false); - Log.d("OnBootReceiver", "Provider configured " + String.valueOf(provider_configured)); - Log.d("OnBootReceiver", "Start on boot " + String.valueOf(start_on_boot)); - if(provider_configured && start_on_boot) { - Intent dashboard_intent = new Intent(context, Dashboard.class); - dashboard_intent.setAction(Constants.ACTION_START_EIP); - dashboard_intent.putExtra(Dashboard.ON_BOOT, true); - dashboard_intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(dashboard_intent); - } + preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Context.MODE_PRIVATE); + boolean provider_configured = !preferences.getString(Provider.KEY, "").isEmpty(); + boolean start_on_boot = preferences.getBoolean(Dashboard.START_ON_BOOT, false); + if (provider_configured && start_on_boot) { + Intent dashboard_intent = new Intent(context, Dashboard.class); + dashboard_intent.setAction(Constants.ACTION_START_EIP); + dashboard_intent.putExtra(Dashboard.ON_BOOT, true); + dashboard_intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(dashboard_intent); + } } } diff --git a/app/src/main/java/se/leap/bitmaskclient/PRNGFixes.java b/app/src/main/java/se/leap/bitmaskclient/PRNGFixes.java index a046f01f..9e523751 100644 --- a/app/src/main/java/se/leap/bitmaskclient/PRNGFixes.java +++ b/app/src/main/java/se/leap/bitmaskclient/PRNGFixes.java @@ -12,28 +12,17 @@ package se.leap.bitmaskclient; * Source: http://android-developers.blogspot.de/2013/08/some-securerandom-thoughts.html */ -import android.os.Build; +import android.os.*; 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 android.util.*; + +import java.io.*; +import java.security.*; 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. - * + * <p/> * 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}. @@ -43,10 +32,13 @@ 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(); + getBuildFingerprintAndDeviceSerial(); - /** Hidden constructor to prevent instantiation. */ - private PRNGFixes() {} + /** + * Hidden constructor to prevent instantiation. + */ + private PRNGFixes() { + } /** * Applies all fixes. @@ -113,7 +105,7 @@ public final class PRNGFixes { if ((secureRandomProviders == null) || (secureRandomProviders.length < 1) || (!LinuxPRNGSecureRandomProvider.class.equals( - secureRandomProviders[0].getClass()))) { + secureRandomProviders[0].getClass()))) { Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1); } @@ -138,7 +130,7 @@ public final class PRNGFixes { rng2.getProvider().getClass())) { throw new SecurityException( "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong" - + " Provider: " + rng2.getProvider().getClass()); + + " Provider: " + rng2.getProvider().getClass()); } } @@ -152,7 +144,7 @@ public final class PRNGFixes { super("LinuxPRNG", 1.0, "A Linux-specific random number provider that uses" - + " /dev/urandom"); + + " /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 diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index d7ff6633..ee06a586 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -1,6 +1,6 @@ /** * 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 @@ -16,66 +16,56 @@ */ package se.leap.bitmaskclient; -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Parcel; -import android.os.Parcelable; +import android.os.*; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import org.json.*; -import java.io.File; -import java.io.Serializable; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Arrays; -import java.util.Locale; +import java.io.*; +import java.net.*; +import java.util.*; /** * @author Sean Leonard <meanderingcode@aetherislands.net> * @author Parménides GV <parmegv@sdf.org> - * */ public final class Provider implements Parcelable { - private JSONObject definition; // Represents our Provider's provider.json + private JSONObject definition; // Represents our Provider's provider.json private URL main_url; 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", - CA_CERT_URI = "ca_cert_uri", - CA_CERT_FINGERPRINT = "ca_cert_fingerprint", - 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"}; - - public Provider(URL main_url) { + API_URL = "api_uri", + API_VERSION = "api_version", + ALLOW_REGISTRATION = "allow_registration", + API_RETURN_SERIAL = "serial", + SERVICE = "service", + KEY = "provider", + CA_CERT = "ca_cert", + CA_CERT_URI = "ca_cert_uri", + CA_CERT_FINGERPRINT = "ca_cert_fingerprint", + 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"}; + + public Provider(URL main_url) { this.main_url = main_url; } public Provider(File provider_file) { } + public static final Parcelable.Creator<Provider> CREATOR = new Parcelable.Creator<Provider>() { public Provider createFromParcel(Parcel in) { @@ -91,7 +81,7 @@ public final class Provider implements Parcelable { try { main_url = new URL(in.readString()); String definition_string = in.readString(); - if(definition_string != null) + if (definition_string != null) definition = new JSONObject((definition_string)); } catch (MalformedURLException e) { e.printStackTrace(); @@ -104,60 +94,62 @@ public final class Provider implements Parcelable { definition = provider_json; } - protected JSONObject definition() { return definition; } + protected JSONObject definition() { + return definition; + } - protected String getDomain(){ - return main_url.getHost(); - } + protected String getDomain() { + return main_url.getHost(); + } protected URL mainUrl() { return main_url; } - - protected String getName(){ - // Should we pass the locale in, or query the system here? - String lang = Locale.getDefault().getLanguage(); - String name = ""; - try { - if(definition != null) - name = definition.getJSONObject(API_TERM_NAME).getString(lang); + + protected String getName() { + // Should we pass the locale in, or query the system here? + String lang = Locale.getDefault().getLanguage(); + String name = ""; + try { + if (definition != null) + name = definition.getJSONObject(API_TERM_NAME).getString(lang); else throw new JSONException("Provider not defined"); - } catch (JSONException e) { - if(main_url != null) { + } catch (JSONException e) { + if (main_url != null) { String host = main_url.getHost(); name = host.substring(0, host.indexOf(".")); } - } - - 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() { - try { + } + + 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() { + try { JSONArray services = definition.getJSONArray(API_TERM_SERVICES); // returns ["openvpn"] - for (int i=0;i<API_EIP_TYPES.length+1;i++){ + 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) ) ) + if (Arrays.asList(API_EIP_TYPES).contains(services.getString(i))) return true; - } catch (NullPointerException e){ + } catch (NullPointerException e) { e.printStackTrace(); return false; } catch (JSONException e) { @@ -166,11 +158,19 @@ public final class Provider implements Parcelable { return false; } } - } catch (Exception e) { - // TODO: handle exception - } - return false; - } + } catch (Exception e) { + // TODO: handle exception + } + return false; + } + + public boolean allowsRegistration() { + try { + return definition.getJSONObject(Provider.SERVICE).getBoolean(Provider.ALLOW_REGISTRATION); + } catch (JSONException e) { + return false; + } + } @Override public int describeContents() { @@ -180,13 +180,13 @@ public final class Provider implements Parcelable { @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeString(main_url.toString()); - if(definition != null) + if (definition != null) parcel.writeString(definition.toString()); } @Override public boolean equals(Object o) { - if(o instanceof Provider) { + if (o instanceof Provider) { Provider p = (Provider) o; return p.mainUrl().getHost().equals(mainUrl().getHost()); } else return false; diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java index 7e4e95d3..533e5caf 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java @@ -1,6 +1,6 @@ /**
* 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
@@ -16,32 +16,30 @@ */
package se.leap.bitmaskclient;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ResultReceiver;
+import android.os.*;
/**
- * Implements the ResultReceiver needed by Activities using ProviderAPI to receive the results of its operations.
- * @author parmegv
+ * 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) {
+ 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
- *
- */
+ /**
+ * Interface to enable ProviderAPIResultReceiver to receive results from the ProviderAPI IntentService.
+ *
+ * @author parmegv
+ */
public interface Receiver {
public void onReceiveResult(int resultCode, Bundle resultData);
}
@@ -52,5 +50,5 @@ public class ProviderAPIResultReceiver extends ResultReceiver { mReceiver.onReceiveResult(resultCode, resultData);
}
}
-
+
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java index c63e2edb..4a34caa0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java @@ -1,44 +1,35 @@ package se.leap.bitmaskclient; -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TwoLineListItem; +import android.view.*; -import com.pedrogomez.renderers.AdapteeCollection; -import com.pedrogomez.renderers.RendererAdapter; -import com.pedrogomez.renderers.RendererBuilder; +import com.pedrogomez.renderers.*; -import java.util.Collection; -import java.util.List; -import java.util.Set; +import java.util.*; public class ProviderListAdapter extends RendererAdapter<Provider> { - 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(); - } + 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 showAllProviders() { - for(int i = 0; i < hidden.length; i++) + for (int i = 0; i < hidden.length; i++) hidden[i] = false; notifyDataSetChanged(); notifyDataSetInvalidated(); } - + public void hideAllBut(int position) { - for (int i = 0; i < hidden.length; i++) { + for (int i = 0; i < hidden.length; i++) { if (i != position) hidden[i] = true; else @@ -47,64 +38,66 @@ public class ProviderListAdapter extends RendererAdapter<Provider> { notifyDataSetChanged(); notifyDataSetInvalidated(); } - - 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()); - } + + 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(LayoutInflater layoutInflater, RendererBuilder rendererBuilder, AdapteeCollection<Provider> collection) { - super(layoutInflater, rendererBuilder, collection); - hidden = new boolean[collection.size()]; - for (int i = 0; i < collection.size(); i++) - hidden[i] = false; + super(layoutInflater, rendererBuilder, collection); + hidden = new boolean[collection.size()]; + for (int i = 0; i < collection.size(); i++) + hidden[i] = false; } - - @Override - public void add(Provider item) { - super.add(item); - if(getCollection().size() > hidden.length) { + + @Override + public void add(Provider item) { + super.add(item); + if (getCollection().size() > hidden.length) { 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(Provider 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 void remove(Provider 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; + } protected int indexOf(Provider item) { int index = 0; diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java index 69bd7c1e..40fe8b5a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java @@ -1,25 +1,14 @@ package se.leap.bitmaskclient; -import android.content.res.AssetManager; - -import com.pedrogomez.renderers.AdapteeCollection; - -import org.json.JSONException; -import org.json.JSONObject; - -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.net.MalformedURLException; -import java.net.URL; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; +import android.content.res.*; + +import com.pedrogomez.renderers.*; + +import org.json.*; + +import java.io.*; +import java.net.*; +import java.util.*; /** * Created by parmegv on 4/12/14. @@ -36,7 +25,7 @@ public class ProviderManager implements AdapteeCollection<Provider> { final protected static String URLS = "urls"; public static ProviderManager getInstance(AssetManager assets_manager, File external_files_dir) { - if(instance == null) + if (instance == null) instance = new ProviderManager(assets_manager); instance.addCustomProviders(external_files_dir); @@ -59,10 +48,10 @@ public class ProviderManager implements AdapteeCollection<Provider> { private Set<Provider> providersFromAssets(String directory, String[] relative_file_paths) { Set<Provider> providers = new HashSet<Provider>(); try { - for(String file : relative_file_paths) { - String main_url = extractMainUrlFromInputStream(assets_manager.open(directory + "/" + file)); + for (String file : relative_file_paths) { + String main_url = extractMainUrlFromInputStream(assets_manager.open(directory + "/" + file)); providers.add(new Provider(new URL(main_url))); - } + } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { @@ -82,7 +71,7 @@ public class ProviderManager implements AdapteeCollection<Provider> { private Set<Provider> providersFromFiles(String[] files) { Set<Provider> providers = new HashSet<Provider>(); try { - for(String file : files) { + for (String file : files) { String main_url = extractMainUrlFromInputStream(new FileInputStream(external_files_dir.getAbsolutePath() + "/" + file)); providers.add(new Provider(new URL(main_url))); } @@ -100,7 +89,7 @@ public class ProviderManager implements AdapteeCollection<Provider> { byte[] bytes = new byte[0]; try { bytes = new byte[input_stream_file_contents.available()]; - if(input_stream_file_contents.read(bytes) > 0) { + if (input_stream_file_contents.read(bytes) > 0) { JSONObject file_contents = new JSONObject(new String(bytes)); main_url = file_contents.getString(Provider.MAIN_URL); } @@ -127,7 +116,7 @@ public class ProviderManager implements AdapteeCollection<Provider> { @Override public Provider get(int index) { Iterator<Provider> iterator = providers().iterator(); - while(iterator.hasNext() && index > 0) { + while (iterator.hasNext() && index > 0) { iterator.next(); index--; } @@ -136,7 +125,7 @@ public class ProviderManager implements AdapteeCollection<Provider> { @Override public void add(Provider element) { - if(!default_providers.contains(element)) + if (!default_providers.contains(element)) custom_providers.add(element); } @@ -163,17 +152,17 @@ public class ProviderManager implements AdapteeCollection<Provider> { } protected void saveCustomProvidersToFile() { - try { - for (Provider provider : custom_providers) { + try { + for (Provider provider : custom_providers) { File provider_file = new File(external_files_dir, provider.getName() + ".json"); - if(!provider_file.exists()) { - FileWriter writer = new FileWriter(provider_file); - writer.write(provider.toJson().toString()); - writer.close(); + if (!provider_file.exists()) { + FileWriter writer = new FileWriter(provider_file); + writer.write(provider.toJson().toString()); + writer.close(); + } } - } - } catch (IOException e) { - e.printStackTrace(); - } + } catch (IOException e) { + e.printStackTrace(); + } } } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderRenderer.java b/app/src/main/java/se/leap/bitmaskclient/ProviderRenderer.java index 6e194e84..4a5d0db1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderRenderer.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderRenderer.java @@ -1,18 +1,12 @@ package se.leap.bitmaskclient; -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import com.pedrogomez.renderers.Renderer; - -import butterknife.ButterKnife; -import butterknife.InjectView; -import butterknife.OnItemClick; -import butterknife.OnItemSelected; +import android.content.*; +import android.view.*; +import android.widget.*; + +import com.pedrogomez.renderers.*; + +import butterknife.*; /** * Created by parmegv on 4/12/14. diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderRendererBuilder.java b/app/src/main/java/se/leap/bitmaskclient/ProviderRendererBuilder.java index 7366e68e..5a6e857d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderRendererBuilder.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderRendererBuilder.java @@ -1,25 +1,19 @@ package se.leap.bitmaskclient; -import android.content.Context; +import com.pedrogomez.renderers.*; -import com.pedrogomez.renderers.Renderer; -import com.pedrogomez.renderers.RendererBuilder; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; - -import javax.inject.Inject; +import java.util.*; /** * Created by parmegv on 4/12/14. */ - public class ProviderRendererBuilder extends RendererBuilder<Provider> { - public ProviderRendererBuilder(Collection<Renderer<Provider>> prototypes) { - super(prototypes); - } - @Override - protected Class getPrototypeClass(Provider content) { - return ProviderRenderer.class; +public class ProviderRendererBuilder extends RendererBuilder<Provider> { + public ProviderRendererBuilder(Collection<Renderer<Provider>> prototypes) { + super(prototypes); + } + + @Override + protected Class getPrototypeClass(Provider content) { + return ProviderRenderer.class; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java b/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java index 9025564b..e92c6b7b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java @@ -1,6 +1,6 @@ /** * 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 @@ -14,42 +14,38 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - package se.leap.bitmaskclient; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.EditText; -import android.widget.TextView; +package se.leap.bitmaskclient; -import org.jetbrains.annotations.NotNull; +import android.app.*; +import android.content.*; +import android.os.*; +import android.view.*; +import android.widget.*; -import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.*; /** * Implements the log in dialog, currently without progress dialog. - * + * <p/> * 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 + * <p/> + * It also notifies the user if the password is not valid. * + * @author parmegv */ -public class SessionDialog extends DialogFragment{ +public class SessionDialog extends DialogFragment { + - final public static String TAG = SessionDialog.class.getSimpleName(); final public static String USERNAME = "username"; final public static String PASSWORD = "password"; - final public static String USERNAME_MISSING = "username missing"; - final public static String PASSWORD_INVALID_LENGTH = "password_invalid_length"; + + public static enum ERRORS { + USERNAME_MISSING, + PASSWORD_INVALID_LENGTH, + RISEUP_WARNING + } @InjectView(R.id.user_message) TextView user_message; @@ -63,63 +59,67 @@ public class SessionDialog extends DialogFragment{ public SessionDialog() { setArguments(Bundle.EMPTY); } - - public AlertDialog onCreateDialog(Bundle savedInstanceState) { - - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - LayoutInflater inflater = getActivity().getLayoutInflater(); - View view = inflater.inflate(R.layout.session_dialog, null); - ButterKnife.inject(this, view); - - Bundle arguments = getArguments(); - if (arguments != Bundle.EMPTY) { + + public AlertDialog onCreateDialog(Bundle savedInstanceState) { + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View view = inflater.inflate(R.layout.session_dialog, null); + ButterKnife.inject(this, view); + + Bundle arguments = getArguments(); + if (arguments != Bundle.EMPTY) { setUp(arguments); - } - - builder.setView(view) - .setPositiveButton(R.string.login_button, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - String username = getEnteredUsername(); - String password = getEnteredPassword(); - dialog.dismiss(); - interface_with_Dashboard.logIn(username, password); - } - }) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - interface_with_Dashboard.cancelLoginOrSignup(); - } - }) - .setNeutralButton(R.string.signup_button, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - String username = getEnteredUsername(); - String password = getEnteredPassword(); - dialog.dismiss(); - interface_with_Dashboard.signUp(username, password); - } - }); - - return builder.create(); - } + } + + builder.setView(view) + .setPositiveButton(R.string.login_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + String username = getEnteredUsername(); + String password = getEnteredPassword(); + dialog.dismiss(); + interface_with_Dashboard.logIn(username, password); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + interface_with_Dashboard.cancelLoginOrSignup(); + } + }) + .setNeutralButton(R.string.signup_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + String username = getEnteredUsername(); + String password = getEnteredPassword(); + dialog.dismiss(); + interface_with_Dashboard.signUp(username, password); + } + }); + + return builder.create(); + } private void setUp(Bundle arguments) { is_eip_pending = arguments.getBoolean(EipFragment.IS_PENDING, false); - if (arguments.containsKey(PASSWORD_INVALID_LENGTH)) + if (arguments.containsKey(ERRORS.PASSWORD_INVALID_LENGTH.toString())) password_field.setError(getString(R.string.error_not_valid_password_user_message)); + else if (arguments.containsKey(ERRORS.RISEUP_WARNING.toString())) { + user_message.setVisibility(TextView.VISIBLE); + user_message.setText(R.string.login_riseup_warning); + } if (arguments.containsKey(USERNAME)) { String username = arguments.getString(USERNAME); username_field.setText(username); } - if (arguments.containsKey(USERNAME_MISSING)) { + if (arguments.containsKey(ERRORS.USERNAME_MISSING.toString())) { username_field.setError(getString(R.string.username_ask)); } - if(arguments.containsKey(getString(R.string.user_message))) + if (arguments.containsKey(getString(R.string.user_message))) user_message.setText(arguments.getString(getString(R.string.user_message))); - else + else if (user_message.getVisibility() != TextView.VISIBLE) user_message.setVisibility(View.GONE); - if(!username_field.getText().toString().isEmpty() && password_field.isFocusable()) + if (!username_field.getText().toString().isEmpty() && password_field.isFocusable()) password_field.requestFocus(); } @@ -132,26 +132,27 @@ public class SessionDialog extends DialogFragment{ return password_field.getText().toString(); } - - /** - * Interface used to communicate SessionDialog with Dashboard. - * - * @author parmegv - * - */ - public interface SessionDialogInterface { - public void logIn(String username, String password); - public void signUp(String username, String password); - public void cancelLoginOrSignup(); + + /** + * Interface used to communicate SessionDialog with Dashboard. + * + * @author parmegv + */ + public interface SessionDialogInterface { + public void logIn(String username, String password); + + public void signUp(String username, String password); + + public void cancelLoginOrSignup(); } - SessionDialogInterface interface_with_Dashboard; - + SessionDialogInterface interface_with_Dashboard; + @Override public void onAttach(Activity activity) { super.onAttach(activity); try { - interface_with_Dashboard = (SessionDialogInterface) activity; + interface_with_Dashboard = (SessionDialogInterface) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement LogInDialogListener"); @@ -160,8 +161,8 @@ public class SessionDialog extends DialogFragment{ @Override public void onCancel(DialogInterface dialog) { - super.onCancel(dialog); - if(is_eip_pending) - interface_with_Dashboard.cancelLoginOrSignup(); + super.onCancel(dialog); + if (is_eip_pending) + interface_with_Dashboard.cancelLoginOrSignup(); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/User.java b/app/src/main/java/se/leap/bitmaskclient/User.java new file mode 100644 index 00000000..4bbd9a91 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/User.java @@ -0,0 +1,44 @@ +/** + * 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; + +public class User { + private static String user_name = "You"; + private static User user; + + public static User getInstance() { + if (user == null) { + user = new User(); + } + return user; + } + + public static void setUserName(String user_name) { + User.user_name = user_name; + } + + private User() { + } + + public static String userName() { + return user_name; + } + + public static boolean loggedIn() { + return LeapSRPSession.loggedIn(); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java b/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java new file mode 100644 index 00000000..e43c8a25 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java @@ -0,0 +1,87 @@ +/** + * 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.*; + +import java.util.*; + +public class UserSessionStatus extends Observable { + public static String TAG = UserSessionStatus.class.getSimpleName(); + private static UserSessionStatus current_status; + + public enum SessionStatus { + LOGGED_IN, + LOGGED_OUT, + NOT_LOGGED_IN, + DIDNT_LOG_OUT, + LOGGING_IN, + LOGGING_OUT, + SIGNING_UP + } + + private static SessionStatus session_status = SessionStatus.NOT_LOGGED_IN; + + public static UserSessionStatus getInstance() { + if (current_status == null) { + current_status = new UserSessionStatus(); + } + return current_status; + } + + private UserSessionStatus() { + } + + private void sessionStatus(SessionStatus session_status) { + this.session_status = session_status; + } + + public SessionStatus sessionStatus() { + return session_status; + } + + public boolean inProgress() { + return session_status == SessionStatus.LOGGING_IN + || session_status == SessionStatus.LOGGING_OUT; + } + + public static void updateStatus(SessionStatus session_status) { + current_status = getInstance(); + current_status.sessionStatus(session_status); + current_status.setChanged(); + current_status.notifyObservers(); + } + + @Override + public String toString() { + String username = User.userName(); + + return username + " " + conjugateToBe(username) + " " + + session_status.toString().toLowerCase().replaceAll("_", " "); + } + + private String conjugateToBe(String subject) { + String conjugation = ""; + if(subject.equalsIgnoreCase("I")) + conjugation = "am"; + else if(subject.equalsIgnoreCase("you") || subject.equalsIgnoreCase("we")|| subject.equalsIgnoreCase("they")) + conjugation = "are"; + else conjugation = "is"; + + return conjugation; + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java b/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java index 12c2e015..39ad7c08 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java @@ -1,6 +1,6 @@ /** * 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 @@ -17,17 +17,14 @@ package se.leap.bitmaskclient.eip; /** - * * Constants for intent passing, shared preferences * * @author Parménides GV <parmegv@sdf.org> - * */ public interface Constants { public final static String TAG = Constants.class.getSimpleName(); - - public final static String AUTHED_EIP = TAG + ".AUTHED_EIP"; + public final static String ACTION_CHECK_CERT_VALIDITY = TAG + ".CHECK_CERT_VALIDITY"; public final static String ACTION_START_EIP = TAG + ".START_EIP"; public final static String ACTION_STOP_EIP = TAG + ".STOP_EIP"; diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java index 3b72a486..beed7948 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -1,6 +1,6 @@ /** * 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 @@ -19,7 +19,6 @@ package se.leap.bitmaskclient.eip; import android.app.*; import android.content.*; import android.os.*; -import android.util.Log; import org.json.*; @@ -34,7 +33,7 @@ import static se.leap.bitmaskclient.eip.Constants.*; * this IntentService. * Contains logic for parsing eip-service.json from the provider, configuring and selecting * gateways, and controlling {@link de.blinkt.openvpn.core.OpenVPNService} connections. - * + * * @author Sean Leonard <meanderingcode@aetherislands.net> * @author Parménides GV <parmegv@sdf.org> */ @@ -44,64 +43,64 @@ public final class EIP extends IntentService { public final static String SERVICE_API_PATH = "config/eip-service.json"; public static final int DISCONNECT = 15; - + private static Context context; private static ResultReceiver mReceiver; private static SharedPreferences preferences; - + private static JSONObject eip_definition; private static GatewaysManager gateways_manager = new GatewaysManager(); private static Gateway gateway; - - public EIP(){ - super(TAG); + + public EIP() { + super(TAG); } - + @Override public void onCreate() { - super.onCreate(); - - context = getApplicationContext(); + super.onCreate(); + + context = getApplicationContext(); preferences = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE); - eip_definition = eipDefinitionFromPreferences(); - if(gateways_manager.isEmpty()) + eip_definition = eipDefinitionFromPreferences(); + if (gateways_manager.isEmpty()) gatewaysFromPreferences(); } @Override protected void onHandleIntent(Intent intent) { - String action = intent.getAction(); - mReceiver = intent.getParcelableExtra(RECEIVER_TAG); - - if ( action.equals(ACTION_START_EIP)) - startEIP(); - else if (action.equals(ACTION_STOP_EIP)) - stopEIP(); - else if (action.equals(ACTION_IS_EIP_RUNNING)) - isRunning(); + String action = intent.getAction(); + mReceiver = intent.getParcelableExtra(RECEIVER_TAG); + + if (action.equals(ACTION_START_EIP)) + startEIP(); + else if (action.equals(ACTION_STOP_EIP)) + stopEIP(); + else if (action.equals(ACTION_IS_EIP_RUNNING)) + isRunning(); else if (action.equals(ACTION_UPDATE_EIP_SERVICE)) - updateEIPService(); - else if (action.equals(ACTION_CHECK_CERT_VALIDITY)) - checkCertValidity(); + updateEIPService(); + else if (action.equals(ACTION_CHECK_CERT_VALIDITY)) + checkCertValidity(); } - + /** * Initiates an EIP connection by selecting a gateway and preparing and sending an * Intent to {@link de.blinkt.openvpn.LaunchVPN}. * It also sets up early routes. */ private void startEIP() { - if(gateways_manager.isEmpty()) - updateEIPService(); + if (gateways_manager.isEmpty()) + updateEIPService(); earlyRoutes(); - gateway = gateways_manager.select(); - if(gateway != null && gateway.getProfile() != null) { - mReceiver = EipFragment.getReceiver(); - launchActiveGateway(); - tellToReceiver(ACTION_START_EIP, Activity.RESULT_OK); - } else - tellToReceiver(ACTION_START_EIP, Activity.RESULT_CANCELED); + gateway = gateways_manager.select(); + if (gateway != null && gateway.getProfile() != null) { + mReceiver = EipFragment.getReceiver(); + launchActiveGateway(); + tellToReceiver(ACTION_START_EIP, Activity.RESULT_OK); + } else + tellToReceiver(ACTION_START_EIP, Activity.RESULT_CANCELED); } /** @@ -109,40 +108,40 @@ public final class EIP extends IntentService { * VpnService is started properly. */ private void earlyRoutes() { - Intent void_vpn_launcher = new Intent(context, VoidVpnLauncher.class); - void_vpn_launcher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(void_vpn_launcher); + Intent void_vpn_launcher = new Intent(context, VoidVpnLauncher.class); + void_vpn_launcher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(void_vpn_launcher); } - + private void launchActiveGateway() { - Intent intent = new Intent(this,LaunchVPN.class); - intent.setAction(Intent.ACTION_MAIN); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(LaunchVPN.EXTRA_NAME, gateway.getProfile().getName()); - intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); - startActivity(intent); + Intent intent = new Intent(this, LaunchVPN.class); + intent.setAction(Intent.ACTION_MAIN); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(LaunchVPN.EXTRA_NAME, gateway.getProfile().getName()); + intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); + startActivity(intent); } private void stopEIP() { - EipStatus eip_status = EipStatus.getInstance(); - int result_code = Activity.RESULT_CANCELED; - if(eip_status.isConnected() || eip_status.isConnecting()) - result_code = Activity.RESULT_OK; + EipStatus eip_status = EipStatus.getInstance(); + int result_code = Activity.RESULT_CANCELED; + if (eip_status.isConnected() || eip_status.isConnecting()) + result_code = Activity.RESULT_OK; - tellToReceiver(ACTION_STOP_EIP, result_code); + tellToReceiver(ACTION_STOP_EIP, result_code); } - + /** * Checks the last stored status notified by ics-openvpn * Sends <code>Activity.RESULT_CANCELED</code> to the ResultReceiver that made the * request if it's not connected, <code>Activity.RESULT_OK</code> otherwise. */ private void isRunning() { - EipStatus eip_status = EipStatus.getInstance(); - int resultCode = (eip_status.isConnected()) ? - Activity.RESULT_OK : - Activity.RESULT_CANCELED; - tellToReceiver(ACTION_IS_EIP_RUNNING, resultCode); + EipStatus eip_status = EipStatus.getInstance(); + int resultCode = (eip_status.isConnected()) ? + Activity.RESULT_OK : + Activity.RESULT_CANCELED; + tellToReceiver(ACTION_IS_EIP_RUNNING, resultCode); } /** @@ -150,27 +149,27 @@ public final class EIP extends IntentService { * TODO Implement API call to refresh eip-service.json from the provider */ private void updateEIPService() { - eip_definition = eipDefinitionFromPreferences(); - if(eip_definition.length() > 0) + eip_definition = eipDefinitionFromPreferences(); + if (eip_definition.length() > 0) updateGateways(); - tellToReceiver(ACTION_UPDATE_EIP_SERVICE, Activity.RESULT_OK); + tellToReceiver(ACTION_UPDATE_EIP_SERVICE, Activity.RESULT_OK); } private JSONObject eipDefinitionFromPreferences() { JSONObject result = new JSONObject(); - try { - String eip_definition_string = preferences.getString(KEY, ""); - if(!eip_definition_string.isEmpty()) { - result = new JSONObject(eip_definition_string); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + try { + String eip_definition_string = preferences.getString(KEY, ""); + if (!eip_definition_string.isEmpty()) { + result = new JSONObject(eip_definition_string); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } return result; } - private void updateGateways(){ + private void updateGateways() { gateways_manager.fromEipServiceJson(eip_definition); gatewaysToPreferences(); } @@ -188,15 +187,15 @@ public final class EIP extends IntentService { } private void checkCertValidity() { - VpnCertificateValidator validator = new VpnCertificateValidator(preferences.getString(CERTIFICATE, "")); - int resultCode = validator.isValid() ? - Activity.RESULT_OK : - Activity.RESULT_CANCELED; - tellToReceiver(ACTION_CHECK_CERT_VALIDITY, resultCode); + VpnCertificateValidator validator = new VpnCertificateValidator(preferences.getString(CERTIFICATE, "")); + int resultCode = validator.isValid() ? + Activity.RESULT_OK : + Activity.RESULT_CANCELED; + tellToReceiver(ACTION_CHECK_CERT_VALIDITY, resultCode); } private void tellToReceiver(String action, int resultCode) { - if (mReceiver != null){ + if (mReceiver != null) { Bundle resultData = new Bundle(); resultData.putString(REQUEST_TAG, action); mReceiver.send(resultCode, resultData); diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java index 4ac3bd6a..ad68f96e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java @@ -1,6 +1,6 @@ /** * 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 @@ -16,11 +16,11 @@ */ package se.leap.bitmaskclient.eip; -import android.util.Log; +import android.content.*; -import java.util.Observable; +import java.util.*; -import de.blinkt.openvpn.core.VpnStatus; +import de.blinkt.openvpn.core.*; public class EipStatus extends Observable implements VpnStatus.StateListener { public static String TAG = EipStatus.class.getSimpleName(); @@ -33,106 +33,123 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { private int localized_res_id; public static EipStatus getInstance() { - if(current_status == null) { - current_status = new EipStatus(); - VpnStatus.addStateListener(current_status); - } - return current_status; + if (current_status == null) { + current_status = new EipStatus(); + VpnStatus.addStateListener(current_status); + } + return current_status; } - private EipStatus() { } + private EipStatus() { + } @Override public void updateState(final String state, final String logmessage, final int localizedResId, final VpnStatus.ConnectionStatus level) { - current_status = getInstance(); - current_status.setState(state); - current_status.setLogMessage(logmessage); - current_status.setLocalizedResId(localizedResId); - current_status.setLevel(level); - current_status.setChanged(); - if(isConnected() || isDisconnected()) - setConnectedOrDisconnected(); - else if(isConnecting()) - setConnecting(); - Log.d(TAG, "update state with level " + level); - current_status.notifyObservers(); + updateStatus(state, logmessage, localizedResId, level); + if (isConnected() || isDisconnected()) { + setConnectedOrDisconnected(); + } else if (isConnecting()) + setConnecting(); + } + + private void updateStatus(final String state, final String logmessage, final int localizedResId, final VpnStatus.ConnectionStatus level) { + current_status = getInstance(); + current_status.setState(state); + current_status.setLogMessage(logmessage); + current_status.setLocalizedResId(localizedResId); + current_status.setLevel(level); + current_status.setChanged(); } public boolean wantsToDisconnect() { - return wants_to_disconnect; + return wants_to_disconnect; } public boolean isConnecting() { - return - !isConnected() && - !isDisconnected() && - !isPaused(); + return + !isConnected() && + !isDisconnected() && + !isPaused(); } public boolean isConnected() { - return level == VpnStatus.ConnectionStatus.LEVEL_CONNECTED; + return level == VpnStatus.ConnectionStatus.LEVEL_CONNECTED; } public boolean isDisconnected() { - return level == VpnStatus.ConnectionStatus.LEVEL_NOTCONNECTED; + return level == VpnStatus.ConnectionStatus.LEVEL_NOTCONNECTED; } public boolean isPaused() { - return level == VpnStatus.ConnectionStatus.LEVEL_VPNPAUSED; + return level == VpnStatus.ConnectionStatus.LEVEL_VPNPAUSED; } public void setConnecting() { - wants_to_disconnect = false; - current_status.setChanged(); - current_status.notifyObservers(); + wants_to_disconnect = false; + current_status.setChanged(); + current_status.notifyObservers(); } public void setConnectedOrDisconnected() { - Log.d(TAG, "setConnectedOrDisconnected()"); - wants_to_disconnect = false; - current_status.setChanged(); - current_status.notifyObservers(); + wants_to_disconnect = false; + current_status.setChanged(); + current_status.notifyObservers(); } public void setDisconnecting() { - wants_to_disconnect = false; + wants_to_disconnect = false; } public String getState() { - return state; + return state; } public String getLogMessage() { - return log_message; + return log_message; } public int getLocalizedResId() { - return localized_res_id; + return localized_res_id; } public VpnStatus.ConnectionStatus getLevel() { - return level; + return level; } private void setState(String state) { - this.state = state; + this.state = state; } private void setLogMessage(String log_message) { - this.log_message = log_message; + this.log_message = log_message; } private void setLocalizedResId(int localized_res_id) { - this.localized_res_id = localized_res_id; + this.localized_res_id = localized_res_id; } private void setLevel(VpnStatus.ConnectionStatus level) { - EipStatus.level = level; + EipStatus.level = level; + } + + public boolean errorInLast(int lines, Context context) { + boolean result = false; + String[] error_keywords = {"error", "ERROR", "fatal", "FATAL"}; + + VpnStatus.LogItem[] log = VpnStatus.getlogbuffer(); + String message = ""; + for (int i = 1; i <= lines && log.length > i; i++) { + message = log[log.length - i].getString(context); + for (int j = 0; j < error_keywords.length; j++) + if (message.contains(error_keywords[j])) + result = true; + } + return result; } @Override public String toString() { - return "State: " + state + " Level: " + level.toString(); + return "State: " + state + " Level: " + level.toString(); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java index 0d8a2f7b..ff7d011e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -1,6 +1,6 @@ /** * 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 @@ -16,32 +16,25 @@ */ package se.leap.bitmaskclient.eip; -import android.app.Activity; -import android.content.SharedPreferences; -import android.util.Log; - -import com.google.gson.Gson; +import com.google.gson.*; -import org.json.JSONException; -import org.json.JSONObject; +import org.json.*; -import java.io.IOException; -import java.io.StringReader; +import java.io.*; -import de.blinkt.openvpn.VpnProfile; -import de.blinkt.openvpn.core.ConfigParser; -import se.leap.bitmaskclient.Dashboard; +import de.blinkt.openvpn.*; +import de.blinkt.openvpn.core.*; /** * Gateway provides objects defining gateways and their metadata. * Each instance contains a VpnProfile for OpenVPN specific data and member * variables describing capabilities and location (name) - * + * * @author Sean Leonard <meanderingcode@aetherislands.net> * @author Parménides GV <parmegv@sdf.org> */ public class Gateway { - + public final static String TAG = Gateway.class.getSimpleName(); private JSONObject general_configuration; @@ -51,86 +44,85 @@ public class Gateway { private String mName; private int timezone; private VpnProfile mVpnProfile; + /** * Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json * and create a VpnProfile belonging to it. */ - public Gateway(JSONObject eip_definition, JSONObject secrets, JSONObject gateway){ + public Gateway(JSONObject eip_definition, JSONObject secrets, JSONObject gateway) { - this.gateway = gateway; + this.gateway = gateway; this.secrets = secrets; - general_configuration = getGeneralConfiguration(eip_definition); - timezone = getTimezone(eip_definition); - mName = locationAsName(eip_definition); + general_configuration = getGeneralConfiguration(eip_definition); + timezone = getTimezone(eip_definition); + mName = locationAsName(eip_definition); - mVpnProfile = createVPNProfile(); - mVpnProfile.mName = mName; + mVpnProfile = createVPNProfile(); + mVpnProfile.mName = mName; } private JSONObject getGeneralConfiguration(JSONObject eip_definition) { - try { - return eip_definition.getJSONObject("openvpn_configuration"); - } catch (JSONException e) { - return new JSONObject(); - } + try { + return eip_definition.getJSONObject("openvpn_configuration"); + } catch (JSONException e) { + return new JSONObject(); + } } private int getTimezone(JSONObject eip_definition) { - JSONObject location = getLocationInfo(eip_definition); - return location.optInt("timezone"); + JSONObject location = getLocationInfo(eip_definition); + return location.optInt("timezone"); } private String locationAsName(JSONObject eip_definition) { - JSONObject location = getLocationInfo(eip_definition); - return location.optString("name"); + JSONObject location = getLocationInfo(eip_definition); + return location.optString("name"); } private JSONObject getLocationInfo(JSONObject eip_definition) { - try { - JSONObject locations = eip_definition.getJSONObject("locations"); + try { + JSONObject locations = eip_definition.getJSONObject("locations"); - return locations.getJSONObject(gateway.getString("location")); - } catch (JSONException e) { - return new JSONObject(); - } + return locations.getJSONObject(gateway.getString("location")); + } catch (JSONException e) { + return new JSONObject(); + } } - + /** * Create and attach the VpnProfile to our gateway object */ - private VpnProfile createVPNProfile(){ - try { - ConfigParser cp = new ConfigParser(); - - VpnConfigGenerator vpn_configuration_generator = new VpnConfigGenerator(general_configuration, secrets, gateway); - String configuration = vpn_configuration_generator.generate(); - - cp.parseConfig(new StringReader(configuration)); - return cp.convertProfile(); - } catch (ConfigParser.ConfigParseError e) { - // FIXME We didn't get a VpnProfile! Error handling! and log level - Log.v(TAG,"Error creating VPNProfile"); - e.printStackTrace(); - return null; - } catch (IOException e) { - // FIXME We didn't get a VpnProfile! Error handling! and log level - Log.v(TAG,"Error creating VPNProfile"); - e.printStackTrace(); - return null; - } + private VpnProfile createVPNProfile() { + try { + ConfigParser cp = new ConfigParser(); + + VpnConfigGenerator vpn_configuration_generator = new VpnConfigGenerator(general_configuration, secrets, gateway); + String configuration = vpn_configuration_generator.generate(); + + cp.parseConfig(new StringReader(configuration)); + return cp.convertProfile(); + } catch (ConfigParser.ConfigParseError e) { + // FIXME We didn't get a VpnProfile! Error handling! and log level + e.printStackTrace(); + return null; + } catch (IOException e) { + // FIXME We didn't get a VpnProfile! Error handling! and log level + e.printStackTrace(); + return null; + } } public String getName() { - return mName; + return mName; } public VpnProfile getProfile() { - return mVpnProfile; + return mVpnProfile; } public int getTimezone() { - return timezone; + return timezone; } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java index 39ae7ca6..90c8f890 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java @@ -1,46 +1,42 @@ package se.leap.bitmaskclient.eip; -import java.util.Calendar; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.TreeMap; +import java.util.*; public class GatewaySelector { List<Gateway> gateways; public GatewaySelector(List<Gateway> gateways) { - this.gateways = gateways; + this.gateways = gateways; } public Gateway select() { - return closestGateway(); + return closestGateway(); } - + private Gateway closestGateway() { - TreeMap<Integer, Set<Gateway>> offsets = calculateOffsets(); - return offsets.isEmpty() ? null : offsets.firstEntry().getValue().iterator().next(); + TreeMap<Integer, Set<Gateway>> offsets = calculateOffsets(); + return offsets.isEmpty() ? null : offsets.firstEntry().getValue().iterator().next(); } - + private TreeMap<Integer, Set<Gateway>> calculateOffsets() { - TreeMap<Integer, Set<Gateway>> offsets = new TreeMap<Integer, Set<Gateway>>(); - int localOffset = Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000; - for(Gateway gateway : gateways) { - int dist = timezoneDistance(localOffset, gateway.getTimezone()); - Set<Gateway> set = (offsets.get(dist) != null) ? - offsets.get(dist) : new HashSet<Gateway>(); - set.add(gateway); - offsets.put(dist, set); - } - return offsets; + TreeMap<Integer, Set<Gateway>> offsets = new TreeMap<Integer, Set<Gateway>>(); + int localOffset = Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000; + for (Gateway gateway : gateways) { + int dist = timezoneDistance(localOffset, gateway.getTimezone()); + Set<Gateway> set = (offsets.get(dist) != null) ? + offsets.get(dist) : new HashSet<Gateway>(); + set.add(gateway); + offsets.put(dist, set); + } + return offsets; } - + private int timezoneDistance(int local_timezone, int remote_timezone) { - // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 - int dist = Math.abs(local_timezone - remote_timezone); - // Farther than 12 timezones and it's shorter around the "back" - if (dist > 12) - dist = 12 - (dist -12); // Well i'll be. Absolute values make equations do funny things. - return dist; + // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 + int dist = Math.abs(local_timezone - remote_timezone); + // Farther than 12 timezones and it's shorter around the "back" + if (dist > 12) + dist = 12 - (dist - 12); // Well i'll be. Absolute values make equations do funny things. + return dist; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 401cd701..1c64328e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -17,7 +17,6 @@ package se.leap.bitmaskclient.eip; import android.content.*; -import android.util.Log; import com.google.gson.*; import com.google.gson.reflect.*; @@ -40,15 +39,18 @@ public class GatewaysManager { private SharedPreferences preferences; private List<Gateway> gateways = new ArrayList<>(); private ProfileManager profile_manager; - private Type list_type = new TypeToken<ArrayList<Gateway>>() {}.getType(); + private Type list_type = new TypeToken<ArrayList<Gateway>>() { + }.getType(); - public GatewaysManager() {} + public GatewaysManager() { + } public GatewaysManager(Context context, SharedPreferences preferences) { this.context = context; this.preferences = preferences; profile_manager = ProfileManager.getInstance(context); } + public Gateway select() { GatewaySelector gateway_selector = new GatewaySelector(gateways); return gateway_selector.select(); @@ -66,16 +68,15 @@ public class GatewaysManager { List<Gateway> gateways_list = new ArrayList<Gateway>(); try { gateways_list = new Gson().fromJson(gateways, list_type); - } catch(JsonSyntaxException e) { + } catch (JsonSyntaxException e) { gateways_list.add(new Gson().fromJson(gateways, Gateway.class)); } - if(gateways_list != null) { + if (gateways_list != null) { for (Gateway gateway : gateways_list) - addGateway(gateway); + addGateway(gateway); this.gateways.addAll(gateways_list); - } else - Log.d("GatewaysManager", "No gateways added"); + } } @Override @@ -85,21 +86,21 @@ public class GatewaysManager { public void fromEipServiceJson(JSONObject eip_definition) { try { - JSONArray gatewaysDefined = eip_definition.getJSONArray("gateways"); - for (int i = 0; i < gatewaysDefined.length(); i++) { - JSONObject gw = gatewaysDefined.getJSONObject(i); - if (isOpenVpnGateway(gw)) { - JSONObject secrets = secretsConfiguration(); - Gateway aux = new Gateway(eip_definition, secrets, gw); - if(!containsProfileWithSecrets(aux.getProfile())) { - addGateway(aux); - } - } - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + JSONArray gatewaysDefined = eip_definition.getJSONArray("gateways"); + for (int i = 0; i < gatewaysDefined.length(); i++) { + JSONObject gw = gatewaysDefined.getJSONObject(i); + if (isOpenVpnGateway(gw)) { + JSONObject secrets = secretsConfiguration(); + Gateway aux = new Gateway(eip_definition, secrets, gw); + if (!containsProfileWithSecrets(aux.getProfile())) { + addGateway(aux); + } + } + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } private boolean isOpenVpnGateway(JSONObject gateway) { @@ -127,10 +128,10 @@ public class GatewaysManager { boolean result = false; Collection<VpnProfile> profiles = profile_manager.getProfiles(); - for(VpnProfile aux : profiles) { + for (VpnProfile aux : profiles) { result = result || sameConnections(profile.mConnections, aux.mConnections) - && profile.mClientCertFilename.equalsIgnoreCase(aux.mClientCertFilename) - && profile.mClientKeyFilename.equalsIgnoreCase(aux.mClientKeyFilename); + && profile.mClientCertFilename.equalsIgnoreCase(aux.mClientCertFilename) + && profile.mClientKeyFilename.equalsIgnoreCase(aux.mClientKeyFilename); } return result; } @@ -149,9 +150,9 @@ public class GatewaysManager { private void removeDuplicatedGateway(Gateway gateway) { Iterator<Gateway> it = gateways.iterator(); List<Gateway> gateways_to_remove = new ArrayList<>(); - while(it.hasNext()) { + while (it.hasNext()) { Gateway aux = it.next(); - if(sameConnections(aux.getProfile().mConnections, gateway.getProfile().mConnections)) { + if (sameConnections(aux.getProfile().mConnections, gateway.getProfile().mConnections)) { gateways_to_remove.add(aux); } } @@ -160,21 +161,21 @@ public class GatewaysManager { } private void removeDuplicatedProfiles(VpnProfile original) { - Collection<VpnProfile> profiles = profile_manager.getProfiles(); + Collection<VpnProfile> profiles = profile_manager.getProfiles(); List<VpnProfile> remove_list = new ArrayList<>(); - for(VpnProfile aux : profiles) { - if (sameConnections(original.mConnections, aux.mConnections)) - remove_list.add(aux); - } + for (VpnProfile aux : profiles) { + if (sameConnections(original.mConnections, aux.mConnections)) + remove_list.add(aux); + } for (VpnProfile profile : remove_list) profile_manager.removeProfile(context, profile); } private boolean sameConnections(Connection[] c1, Connection[] c2) { int same_connections = 0; - for(Connection c1_aux : c1) { - for(Connection c2_aux : c2) - if(c2_aux.mServerName.equals(c1_aux.mServerName)) { + for (Connection c1_aux : c1) { + for (Connection c2_aux : c2) + if (c2_aux.mServerName.equals(c1_aux.mServerName)) { same_connections++; break; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java index d79d8003..5c9263b3 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java @@ -1,9 +1,9 @@ package se.leap.bitmaskclient.eip; -import android.app.Activity; -import android.content.Intent; -import android.net.VpnService; -import android.os.Bundle; +import android.app.*; +import android.content.*; +import android.net.*; +import android.os.*; public class VoidVpnLauncher extends Activity { @@ -11,27 +11,27 @@ public class VoidVpnLauncher extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setUp(); + super.onCreate(savedInstanceState); + setUp(); } - + public void setUp() { - Intent blocking_intent = VpnService.prepare(getApplicationContext()); // stops the VPN connection created by another application. - if(blocking_intent != null) - startActivityForResult(blocking_intent, VPN_USER_PERMISSION); - else { - onActivityResult(VPN_USER_PERMISSION, RESULT_OK, null); - } + Intent blocking_intent = VpnService.prepare(getApplicationContext()); // stops the VPN connection created by another application. + if (blocking_intent != null) + startActivityForResult(blocking_intent, VPN_USER_PERMISSION); + else { + onActivityResult(VPN_USER_PERMISSION, RESULT_OK, null); + } } - protected void onActivityResult(int requestCode, int resultCode, Intent data){ - if(requestCode == VPN_USER_PERMISSION) { - if(resultCode == RESULT_OK) { - Intent void_vpn_service = new Intent(getApplicationContext(), VoidVpnService.class); - void_vpn_service.setAction(Constants.START_BLOCKING_VPN_PROFILE); - startService(void_vpn_service); - } - } - finish(); + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == VPN_USER_PERMISSION) { + if (resultCode == RESULT_OK) { + Intent void_vpn_service = new Intent(getApplicationContext(), VoidVpnService.class); + void_vpn_service.setAction(Constants.START_BLOCKING_VPN_PROFILE); + startService(void_vpn_service); + } + } + finish(); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java index 0c773208..dac92fe2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java @@ -1,53 +1,61 @@ package se.leap.bitmaskclient.eip; -import android.content.Intent; -import android.net.VpnService; -import android.os.ParcelFileDescriptor; +import android.content.*; +import android.net.*; +import android.os.*; -import java.io.IOException; +import java.io.*; -public class VoidVpnService extends VpnService { +public class VoidVpnService extends VpnService { static final String TAG = VoidVpnService.class.getSimpleName(); static ParcelFileDescriptor fd; + static Thread thread; + @Override public int onStartCommand(Intent intent, int flags, int startId) { - String action = intent != null ? intent.getAction() : ""; - if (action == Constants.START_BLOCKING_VPN_PROFILE) { - new Thread(new Runnable() { - public void run() { - Builder builder = new Builder(); - builder.setSession("Blocking until running"); - builder.addAddress("10.42.0.8",16); - builder.addRoute("0.0.0.0", 1); - builder.addRoute("192.168.1.0", 24); - builder.addDnsServer("10.42.0.1"); - try { - fd = builder.establish(); - } catch (Exception e) { - e.printStackTrace(); - } - android.util.Log.d(TAG, "VoidVpnService set up"); - } - }).run(); - } - return 0; + String action = intent != null ? intent.getAction() : ""; + if (action == Constants.START_BLOCKING_VPN_PROFILE) { + thread = new Thread(new Runnable() { + public void run() { + Builder builder = new Builder(); + builder.setSession("Blocking until running"); + builder.addAddress("10.42.0.8", 16); + builder.addRoute("0.0.0.0", 1); + builder.addRoute("192.168.1.0", 24); + builder.addDnsServer("10.42.0.1"); + try { + fd = builder.establish(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + thread.run(); + } + return 0; } @Override public void onRevoke() { super.onRevoke(); + closeFd(); + } + + public static void stop() { + if (thread != null) + thread.interrupt(); + closeFd(); } - public static boolean stop() { + private static void closeFd() { try { - fd.close(); - return true; - } catch (IOException | NullPointerException e) { - android.util.Log.d(TAG, "VoidVpnService didn't stop"); + if (fd != null) + fd.close(); + } catch (IOException e) { e.printStackTrace(); - return false; } } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java index 0bbe9db4..8fce6a37 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java @@ -1,6 +1,6 @@ /** * 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 @@ -16,14 +16,10 @@ */ package se.leap.bitmaskclient.eip; -import android.util.Log; - -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; -import java.security.cert.X509Certificate; -import java.util.Calendar; +import java.security.cert.*; +import java.util.*; -import se.leap.bitmaskclient.ConfigHelper; +import se.leap.bitmaskclient.*; public class VpnCertificateValidator { public final static String TAG = VpnCertificateValidator.class.getSimpleName(); @@ -35,32 +31,30 @@ public class VpnCertificateValidator { } public boolean isValid() { - if(!certificate.isEmpty()) { - X509Certificate certificate_x509 = ConfigHelper.parseX509CertificateFromString(certificate); - return isValid(certificate_x509); - } else return true; + if (!certificate.isEmpty()) { + X509Certificate certificate_x509 = ConfigHelper.parseX509CertificateFromString(certificate); + return isValid(certificate_x509); + } else return true; } - + private boolean isValid(X509Certificate certificate) { - Calendar offset_date = calculateOffsetCertificateValidity(certificate); - try { - Log.d(TAG, "offset_date = " + offset_date.getTime().toString()); - certificate.checkValidity(offset_date.getTime()); - return true; - } catch(CertificateExpiredException e) { - return false; - } catch(CertificateNotYetValidException e) { - return false; - } + Calendar offset_date = calculateOffsetCertificateValidity(certificate); + try { + certificate.checkValidity(offset_date.getTime()); + return true; + } catch (CertificateExpiredException e) { + return false; + } catch (CertificateNotYetValidException e) { + return false; + } } private Calendar calculateOffsetCertificateValidity(X509Certificate certificate) { - Log.d(TAG, "certificate not after = " + certificate.getNotAfter()); - long preventive_time = Math.abs(certificate.getNotBefore().getTime() - certificate.getNotAfter().getTime())/2; - long current_date_millis = Calendar.getInstance().getTimeInMillis(); - - Calendar limit_date = Calendar.getInstance(); - limit_date.setTimeInMillis(current_date_millis + preventive_time); - return limit_date; + long preventive_time = Math.abs(certificate.getNotBefore().getTime() - certificate.getNotAfter().getTime()) / 2; + long current_date_millis = Calendar.getInstance().getTimeInMillis(); + + Calendar limit_date = Calendar.getInstance(); + limit_date.setTimeInMillis(current_date_millis + preventive_time); + return limit_date; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java index 6f260f55..0b9c5832 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java @@ -1,6 +1,6 @@ /** * 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 @@ -16,16 +16,11 @@ */ package se.leap.bitmaskclient.eip; -import android.content.SharedPreferences; -import android.util.Log; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import org.json.*; -import java.util.Iterator; +import java.util.*; -import se.leap.bitmaskclient.Provider; +import se.leap.bitmaskclient.*; public class VpnConfigGenerator { @@ -37,79 +32,79 @@ public class VpnConfigGenerator { private final String new_line = System.getProperty("line.separator"); // Platform new line public VpnConfigGenerator(JSONObject general_configuration, JSONObject secrets, JSONObject gateway) { - this.general_configuration = general_configuration; - this.gateway = gateway; + this.general_configuration = general_configuration; + this.gateway = gateway; this.secrets = secrets; } - + public String generate() { - return - generalConfiguration() - + new_line - + gatewayConfiguration() - + new_line - + secretsConfiguration() - + new_line - + androidCustomizations(); + return + generalConfiguration() + + new_line + + gatewayConfiguration() + + new_line + + secretsConfiguration() + + new_line + + androidCustomizations(); } private String generalConfiguration() { - String common_options = ""; - try { - Iterator keys = general_configuration.keys(); - while ( keys.hasNext() ){ - String key = keys.next().toString(); - - common_options += key + " "; - for ( String word : general_configuration.getString(key).split(" ") ) - common_options += word + " "; - common_options += new_line; - - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - common_options += "client"; - - return common_options; + String common_options = ""; + try { + Iterator keys = general_configuration.keys(); + while (keys.hasNext()) { + String key = keys.next().toString(); + + common_options += key + " "; + for (String word : general_configuration.getString(key).split(" ")) + common_options += word + " "; + common_options += new_line; + + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + common_options += "client"; + + return common_options; } - + private String gatewayConfiguration() { - String remotes = ""; - - String ip_address_keyword = "ip_address"; - String remote_keyword = "remote"; - String ports_keyword = "ports"; - String protocol_keyword = "protocols"; - String capabilities_keyword = "capabilities"; - String udp = "udp"; - - try { - String ip_address = gateway.getString(ip_address_keyword); - JSONObject capabilities = gateway.getJSONObject(capabilities_keyword); - JSONArray ports = capabilities.getJSONArray(ports_keyword); - for (int i=0; i<ports.length(); i++) { - String port_specific_remotes = ""; - int port = ports.getInt(i); - JSONArray protocols = capabilities.getJSONArray(protocol_keyword); - for ( int j=0; j<protocols.length(); j++ ) { - String protocol = protocols.optString(j); - String new_remote = remote_keyword + " " + ip_address + " " + port + " " + protocol + new_line; - - port_specific_remotes = protocol.equalsIgnoreCase(udp) ? - port_specific_remotes.replaceFirst(remote_keyword, new_remote + new_line + remote_keyword) : - new_remote; - } - remotes += port_specific_remotes; - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - return remotes; + String remotes = ""; + + String ip_address_keyword = "ip_address"; + String remote_keyword = "remote"; + String ports_keyword = "ports"; + String protocol_keyword = "protocols"; + String capabilities_keyword = "capabilities"; + String udp = "udp"; + + try { + String ip_address = gateway.getString(ip_address_keyword); + JSONObject capabilities = gateway.getJSONObject(capabilities_keyword); + JSONArray ports = capabilities.getJSONArray(ports_keyword); + for (int i = 0; i < ports.length(); i++) { + String port_specific_remotes = ""; + int port = ports.getInt(i); + JSONArray protocols = capabilities.getJSONArray(protocol_keyword); + for (int j = 0; j < protocols.length(); j++) { + String protocol = protocols.optString(j); + String new_remote = remote_keyword + " " + ip_address + " " + port + " " + protocol + new_line; + + port_specific_remotes = protocol.equalsIgnoreCase(udp) ? + port_specific_remotes.replaceFirst(remote_keyword, new_remote + new_line + remote_keyword) : + new_remote; + } + remotes += port_specific_remotes; + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return remotes; } private String secretsConfiguration() { @@ -136,18 +131,18 @@ public class VpnConfigGenerator { + "</cert>"; return ca + new_line + key + new_line + openvpn_cert; - } catch(JSONException e) { + } catch (JSONException e) { e.printStackTrace(); return ""; } } private String androidCustomizations() { - return - "remote-cert-tls server" - + new_line - + "persist-tun" - + new_line - + "auth-retry nointeract"; + return + "remote-cert-tls server" + + new_line + + "persist-tun" + + new_line + + "auth-retry nointeract"; } } |