diff options
author | Parménides GV <parmegv@sdf.org> | 2014-08-18 18:22:54 +0200 |
---|---|---|
committer | Parménides GV <parmegv@sdf.org> | 2014-08-18 18:22:54 +0200 |
commit | 31f6eab32a26a658cbfb2db0d457cc1f87d23f0f (patch) | |
tree | 75f372ff22a94102ef2f9bd163febf54ac45e9d6 /app/src/main/java/se/leap | |
parent | 6057466bc8b4475bf4564b9143c60753c90f9aaa (diff) | |
parent | 7d8cde4f7ae769a3b6a25483d8bd0bb6c1551af9 (diff) |
Merge branch 'develop'
Diffstat (limited to 'app/src/main/java/se/leap')
4 files changed, 519 insertions, 474 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java index cb451b86..fe546a21 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java +++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java @@ -33,6 +33,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; @@ -63,12 +64,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf public static final String PARAMETERS = "dashboard parameters"; public static final String START_ON_BOOT = "dashboard start on boot"; final public static String ON_BOOT = "dashboard on boot"; + public static final String APP_VERSION = "bitmask version"; - + + private EipServiceFragment eipFragment; private ProgressBar mProgressBar; private TextView eipStatus; private static Context app; - private static SharedPreferences preferences; + protected static SharedPreferences preferences; private static Provider provider; private TextView providerNameTV; @@ -81,17 +84,15 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - app = this; + app = this; PRNGFixes.apply(); - // mProgressBar = (ProgressBar) findViewById(R.id.progressbar_dashboard); - // mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - // eipStatus = (TextView) findViewById(R.id.eipStatus); mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); - + handleVersion(); + authed_eip = preferences.getBoolean(EIP.AUTHED_EIP, false); if (preferences.getString(Provider.KEY, "").isEmpty()) startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); @@ -99,8 +100,21 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false)); } + private void handleVersion() { + try { + int versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode; + int lastDetectedVersion = preferences.getInt(APP_VERSION, 0); + if(lastDetectedVersion == 0) // New install + getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putInt(APP_VERSION, versionCode); + else if(lastDetectedVersion < versionCode) { + } + } catch (NameNotFoundException e) { + } + } + @Override protected void onDestroy() { + super.onDestroy(); } @@ -122,7 +136,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf invalidateOptionsMenu(); if(data != null && data.hasExtra(LogInDialog.VERB)) { View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); - logInDialog(view, Bundle.EMPTY); + logInDialog(Bundle.EMPTY); } } else if(resultCode == RESULT_CANCELED && (data == null || data.hasExtra(ACTION_QUIT))) { finish(); @@ -176,9 +190,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf FragmentManager fragMan = getFragmentManager(); if ( provider.hasEIP()){ - EipServiceFragment eipFragment = new EipServiceFragment(); - if (hide_and_turn_on_eip) { - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().remove(Dashboard.START_ON_BOOT).commit(); + eipFragment = new EipServiceFragment(); + if (hide_and_turn_on_eip) { + getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().remove(Dashboard.START_ON_BOOT).commit(); Bundle arguments = new Bundle(); arguments.putBoolean(EipServiceFragment.START_ON_BOOT, true); eipFragment.setArguments(arguments); @@ -197,8 +211,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf try { provider_json = new JSONObject(getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, "")); JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); - - if(service_description.getBoolean(Provider.ALLOW_REGISTRATION)) { + boolean authed_eip = preferences.getBoolean(EIP.AUTHED_EIP, false); + boolean allow_registered_eip = service_description.getBoolean(Provider.ALLOW_REGISTRATION); + preferences.edit().putBoolean(EIP.ALLOWED_REGISTERED, allow_registered_eip); + if(allow_registered_eip) { if(authed_eip) { menu.findItem(R.id.login_button).setVisible(false); menu.findItem(R.id.logout_button).setVisible(true); @@ -238,15 +254,15 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if (Provider.getInstance().hasEIP()){ if (getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getBoolean(EIP.AUTHED_EIP, false)){ logOut(); - } + } eipStop(); } - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().remove(Provider.KEY).commit(); + getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().clear().commit(); startActivityForResult(new Intent(this,ConfigurationWizard.class), SWITCH_PROVIDER); return true; case R.id.login_button: View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); - logInDialog(view, Bundle.EMPTY); + logInDialog(Bundle.EMPTY); return true; case R.id.logout_button: logOut(); @@ -305,6 +321,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if(eipStatus == null) eipStatus = (TextView) findViewById(R.id.eipStatus); if(eipStatus != null) eipStatus.setText(""); } + cancelAuthedEipOn(); } /** @@ -343,9 +360,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf /** * Shows the log in dialog. - * @param view from which the dialog is created. */ - public void logInDialog(View view, Bundle resultData) { + public void logInDialog(Bundle resultData) { + Log.d("Dashboard", "Log In Dialog"); FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(LogInDialog.TAG); if (previous_log_in_dialog != null) { @@ -455,7 +472,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf //Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); downloadAuthedUserCertificate(/*session_id*/); } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_FAILED) { - logInDialog(getCurrentFocus(), resultData); + logInDialog(resultData); } else if(resultCode == ProviderAPI.LOGOUT_SUCCESSFUL) { authed_eip = false; getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); @@ -468,13 +485,16 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } else if(resultCode == ProviderAPI.LOGOUT_FAILED) { setResult(RESULT_CANCELED); changeStatusMessage(resultCode); - mProgressBar.setVisibility(ProgressBar.GONE); + mProgressBar.setVisibility(ProgressBar.GONE); } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_OK); changeStatusMessage(resultCode); - mProgressBar.setVisibility(ProgressBar.GONE); + if(mProgressBar != null) + mProgressBar.setVisibility(ProgressBar.GONE); if(EipServiceFragment.isEipSwitchChecked()) eipStart(); + else + eipStatus.setText(R.string.eip_state_not_connected); } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); changeStatusMessage(resultCode); @@ -570,4 +590,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startService(eip_intent); } + + protected void setProgressBarVisibility(int visibility) { + if(mProgressBar == null) + mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); + mProgressBar.setVisibility(visibility); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index 21a573fe..41299318 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -16,35 +16,9 @@ */ package se.leap.bitmaskclient; -import java.io.StringReader; -import java.io.IOException; -import java.util.Calendar; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.TreeMap; -import java.util.Vector; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.Dashboard; -import se.leap.bitmaskclient.Provider; -import de.blinkt.openvpn.activities.DisconnectVPN; -import de.blinkt.openvpn.core.ConfigParser; -import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; -import de.blinkt.openvpn.LaunchVPN; -import de.blinkt.openvpn.core.OpenVpnManagementThread; -import de.blinkt.openvpn.core.OpenVpnService; -import de.blinkt.openvpn.core.OpenVpnService.LocalBinder; -import de.blinkt.openvpn.core.ProfileManager; -import de.blinkt.openvpn.VpnProfile; import android.app.Activity; import android.app.IntentService; @@ -58,6 +32,41 @@ import android.os.Bundle; import android.os.IBinder; import android.os.ResultReceiver; import android.util.Log; +import de.blinkt.openvpn.LaunchVPN; +import de.blinkt.openvpn.VpnProfile; +import de.blinkt.openvpn.activities.DisconnectVPN; +import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; +import de.blinkt.openvpn.core.ConfigParser; +import de.blinkt.openvpn.core.OpenVpnManagementThread; +import de.blinkt.openvpn.core.OpenVpnService.LocalBinder; +import de.blinkt.openvpn.core.OpenVpnService; +import de.blinkt.openvpn.core.ProfileManager; +import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; +import java.io.IOException; +import java.io.StringReader; +import java.lang.StringBuffer; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Calendar; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.TreeMap; +import java.util.Vector; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import se.leap.bitmaskclient.Dashboard; +import se.leap.bitmaskclient.Provider; +import se.leap.bitmaskclient.R; /** * EIP is the abstract base class for interacting with and managing the Encrypted @@ -72,13 +81,16 @@ import android.util.Log; public final class EIP extends IntentService { public final static String AUTHED_EIP = "authed eip"; + public final static String ACTION_CHECK_CERT_VALIDITY = "se.leap.bitmaskclient.CHECK_CERT_VALIDITY"; public final static String ACTION_START_EIP = "se.leap.bitmaskclient.START_EIP"; public final static String ACTION_STOP_EIP = "se.leap.bitmaskclient.STOP_EIP"; public final static String ACTION_UPDATE_EIP_SERVICE = "se.leap.bitmaskclient.UPDATE_EIP_SERVICE"; public final static String ACTION_IS_EIP_RUNNING = "se.leap.bitmaskclient.IS_RUNNING"; public final static String EIP_NOTIFICATION = "EIP_NOTIFICATION"; public final static String STATUS = "eip status"; + public final static String DATE_FROM_CERTIFICATE = "date from certificate"; public final static String ALLOWED_ANON = "allow_anonymous"; + public final static String ALLOWED_REGISTERED = "allow_registration"; public final static String CERTIFICATE = "cert"; public final static String PRIVATE_KEY = "private_key"; public final static String KEY = "eip"; @@ -87,8 +99,9 @@ public final class EIP extends IntentService { public final static String RECEIVER_TAG = "receiverTag"; public final static String REQUEST_TAG = "requestTag"; public final static String TAG = "se.leap.bitmaskclient.EIP"; - - + + public final static SimpleDateFormat certificate_date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US); + private static Context context; private static ResultReceiver mReceiver; private static OpenVpnService mVpnService; @@ -100,6 +113,10 @@ public final class EIP extends IntentService { private static JSONObject eipDefinition = null; private static OVPNGateway activeGateway = null; + + protected static ConnectionStatus lastConnectionStatusLevel; + protected static boolean mIsDisconnecting = false; + protected static boolean mIsStarting = false; public EIP(){ super("LEAPEIP"); @@ -112,13 +129,11 @@ public final class EIP extends IntentService { context = getApplicationContext(); updateEIPService(); - - this.retreiveVpnService(); } @Override public void onDestroy() { - unbindService(mVpnServiceConn); + mBound = false; super.onDestroy(); @@ -138,108 +153,30 @@ public final class EIP extends IntentService { this.startEIP(); else if ( action == ACTION_STOP_EIP ) this.stopEIP(); + else if ( action == ACTION_CHECK_CERT_VALIDITY ) + this.checkCertValidity(); } /** - * Sends an Intent to bind OpenVpnService. - * Used when OpenVpnService isn't bound but might be running. - */ - private boolean retreiveVpnService() { - Intent bindIntent = new Intent(this,OpenVpnService.class); - bindIntent.setAction(OpenVpnService.START_SERVICE); - return bindService(bindIntent, mVpnServiceConn, BIND_AUTO_CREATE); - } - - private ServiceConnection mVpnServiceConn = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - LocalBinder binder = (LocalBinder) service; - mVpnService = binder.getService(); - mBound = true; - - if (mReceiver != null && mPending != null) { - - boolean running = isConnected(); - - int resultCode = Activity.RESULT_CANCELED; - - if (mPending.equals(ACTION_IS_EIP_RUNNING)){ - resultCode = (running) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - - } - else if (mPending.equals(ACTION_START_EIP)){ - resultCode = (running) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - } - else if (mPending.equals(ACTION_STOP_EIP)){ - resultCode = (running) ? Activity.RESULT_CANCELED - : Activity.RESULT_OK; - } - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); - mReceiver.send(resultCode, resultData); - - mPending = null; - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mBound = false; - - if (mReceiver != null){ - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, EIP_NOTIFICATION); - mReceiver.send(Activity.RESULT_CANCELED, resultData); - } - } - - - }; - - /** - * Attempts to determine if OpenVpnService has an established VPN connection - * through the bound ServiceConnection. If there is no bound service, this - * method will attempt to bind a running OpenVpnService and send - * <code>Activity.RESULT_CANCELED</code> to the ResultReceiver that made the - * request. - * Note: If the request to bind OpenVpnService is successful, the ResultReceiver - * will be notified in {@link onServiceConnected()} + * 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() { - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); - int resultCode = Activity.RESULT_CANCELED; - boolean is_connected = isConnected(); - if (mBound) { - resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; + Bundle resultData = new Bundle(); + resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); + int resultCode = Activity.RESULT_CANCELED; + boolean is_connected = isConnected(); + + resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - if (mReceiver != null){ - mReceiver.send(resultCode, resultData); - } - } else { - mPending = ACTION_IS_EIP_RUNNING; - boolean retrieved_vpn_service = retreiveVpnService(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - boolean running = is_connected; - - if (retrieved_vpn_service && running && mReceiver != null){ - mReceiver.send(Activity.RESULT_OK, resultData); - } - else{ - mReceiver.send(Activity.RESULT_CANCELED, resultData); - } - } - } - - private boolean isConnected() { - return getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(STATUS, "").equalsIgnoreCase("LEVEL_CONNECTED"); - } + if (mReceiver != null){ + mReceiver.send(resultCode, resultData); + } + + Log.d(TAG, "isRunning() = " + is_connected); + } /** * Initiates an EIP connection by selecting a gateway and preparing and sending an @@ -249,31 +186,36 @@ public final class EIP extends IntentService { activeGateway = selectGateway(); if(activeGateway != null && activeGateway.mVpnProfile != null) { - Intent intent = new Intent(this,LaunchVPN.class); - intent.setAction(Intent.ACTION_MAIN); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(LaunchVPN.EXTRA_KEY, activeGateway.mVpnProfile.getUUID().toString() ); - intent.putExtra(LaunchVPN.EXTRA_NAME, activeGateway.mVpnProfile.getName() ); - intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); - intent.putExtra(RECEIVER_TAG, mReceiver); - startActivity(intent); - mPending = ACTION_START_EIP; + launchActiveGateway(); } } + + 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_KEY, activeGateway.mVpnProfile.getUUID().toString() ); + intent.putExtra(LaunchVPN.EXTRA_NAME, activeGateway.mVpnProfile.getName() ); + intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); + intent.putExtra(RECEIVER_TAG, mReceiver); + startActivity(intent); + mPending = ACTION_START_EIP; + } /** * Disconnects the EIP connection gracefully through the bound service or forcefully * if there is no bound service. Sends a message to the requesting ResultReceiver. */ private void stopEIP() { - if (mBound) - mVpnService.onRevoke(); - else if(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(STATUS, "").startsWith("LEVEL_CONNECT")){ + if(isConnected()) { Intent disconnect_vpn = new Intent(this, DisconnectVPN.class); disconnect_vpn.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(disconnect_vpn); + mIsDisconnecting = true; + lastConnectionStatusLevel = ConnectionStatus.UNKNOWN_LEVEL; // Wait for the decision of the user + Log.d(TAG, "mIsDisconnecting = true"); } - + if (mReceiver != null){ Bundle resultData = new Bundle(); resultData.putString(REQUEST_TAG, ACTION_STOP_EIP); @@ -281,6 +223,10 @@ public final class EIP extends IntentService { } } + protected static boolean isConnected() { + return lastConnectionStatusLevel != null && lastConnectionStatusLevel.equals(ConnectionStatus.LEVEL_CONNECTED) && !mIsDisconnecting; + } + /** * Loads eip-service.json from SharedPreferences and calls {@link updateGateways()} * to parse gateway definitions. @@ -295,62 +241,27 @@ public final class EIP extends IntentService { e.printStackTrace(); } if(parsedEipSerial == 0) { - // Delete all vpn profiles - ProfileManager vpl = ProfileManager.getInstance(context); - VpnProfile[] profiles = (VpnProfile[]) vpl.getProfiles().toArray(new VpnProfile[vpl.getProfiles().size()]); - for (int current_profile = 0; current_profile < profiles.length; current_profile++){ - vpl.removeProfile(context, profiles[current_profile]); - } + deleteAllVpnProfiles(); } - if (eipDefinition.optInt("serial") > parsedEipSerial) + if (eipDefinition != null && eipDefinition.optInt("serial") > parsedEipSerial) updateGateways(); } - + + private void deleteAllVpnProfiles() { + ProfileManager vpl = ProfileManager.getInstance(context); + VpnProfile[] profiles = (VpnProfile[]) vpl.getProfiles().toArray(new VpnProfile[vpl.getProfiles().size()]); + for (int current_profile = 0; current_profile < profiles.length; current_profile++){ + vpl.removeProfile(context, profiles[current_profile]); + } + } /** * Choose a gateway to connect to based on timezone from system locale data * * @return The gateway to connect to */ private OVPNGateway selectGateway() { - // TODO Remove String arg constructor in favor of findGatewayByName(String) + String closestLocation = closestGateway(); - Calendar cal = Calendar.getInstance(); - int localOffset = cal.get(Calendar.ZONE_OFFSET) / 3600000; - TreeMap<Integer, Set<String>> offsets = new TreeMap<Integer, Set<String>>(); - JSONObject locationsObjects = null; - Iterator<String> locations = null; - try { - locationsObjects = eipDefinition.getJSONObject("locations"); - locations = locationsObjects.keys(); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - while (locations.hasNext()) { - String locationName = locations.next(); - JSONObject location = null; - try { - location = locationsObjects.getJSONObject(locationName); - - // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 - int dist = Math.abs(localOffset - location.optInt("timezone")); - // Farther than 12 timezones and it's shorter around the "back" - if (dist > 12) - dist = 12 - (dist -12); // Well i'll be. Absolute values make equations do funny things. - - Set<String> set = offsets.get(dist); - if (set == null) set = new HashSet<String>(); - set.add(locationName); - offsets.put(dist, set); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - - String closestLocation = offsets.isEmpty() ? "" : offsets.firstEntry().getValue().iterator().next(); JSONArray gateways = null; String chosenHost = null; try { @@ -358,7 +269,7 @@ public final class EIP extends IntentService { for (int i = 0; i < gateways.length(); i++) { JSONObject gw = gateways.getJSONObject(i); if ( gw.getString("location").equalsIgnoreCase(closestLocation) || closestLocation.isEmpty()){ - chosenHost = gw.getString("host"); + chosenHost = eipDefinition.getJSONObject("locations").getJSONObject(gw.getString("location")).getString("name"); break; } } @@ -369,6 +280,44 @@ public final class EIP extends IntentService { return new OVPNGateway(chosenHost); } + + private String closestGateway() { + Calendar cal = Calendar.getInstance(); + int localOffset = cal.get(Calendar.ZONE_OFFSET) / 3600000; + TreeMap<Integer, Set<String>> offsets = new TreeMap<Integer, Set<String>>(); + JSONObject locationsObjects = null; + Iterator<String> locations = null; + try { + locationsObjects = eipDefinition.getJSONObject("locations"); + locations = locationsObjects.keys(); + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + while (locations.hasNext()) { + String locationName = locations.next(); + JSONObject location = null; + try { + location = locationsObjects.getJSONObject(locationName); + + // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 + int dist = Math.abs(localOffset - location.optInt("timezone")); + // Farther than 12 timezones and it's shorter around the "back" + if (dist > 12) + dist = 12 - (dist -12); // Well i'll be. Absolute values make equations do funny things. + + Set<String> set = offsets.get(dist); + if (set == null) set = new HashSet<String>(); + set.add(locationName); + offsets.put(dist, set); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return offsets.isEmpty() ? "" : offsets.firstEntry().getValue().iterator().next(); + } /** * Walk the list of gateways defined in eip-service.json and parse them into @@ -379,35 +328,55 @@ public final class EIP extends IntentService { JSONArray gatewaysDefined = null; try { - gatewaysDefined = eipDefinition.getJSONArray("gateways"); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - for ( int i=0 ; i < gatewaysDefined.length(); i++ ){ - - JSONObject gw = null; - - try { - gw = gatewaysDefined.getJSONObject(i); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + gatewaysDefined = eipDefinition.getJSONArray("gateways"); + for ( int i=0 ; i < gatewaysDefined.length(); i++ ){ + JSONObject gw = null; + gw = gatewaysDefined.getJSONObject(i); - try { - if ( gw.getJSONObject("capabilities").getJSONArray("transport").toString().contains("openvpn") ){ - new OVPNGateway(gw); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + if ( gw.getJSONObject("capabilities").getJSONArray("transport").toString().contains("openvpn") ) + new OVPNGateway(gw); } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } + getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putInt(PARSED_SERIAL, eipDefinition.optInt(Provider.API_RETURN_SERIAL)).commit(); } + private void checkCertValidity() { + String certificate_string = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(CERTIFICATE, ""); + if(!certificate_string.isEmpty()) { + String date_from_certificate_string = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(DATE_FROM_CERTIFICATE, certificate_date_format.format(Calendar.getInstance().getTime()).toString()); + X509Certificate certificate_x509 = ConfigHelper.parseX509CertificateFromString(certificate_string); + + Calendar offset_date = Calendar.getInstance(); + try { + Date date_from_certificate = certificate_date_format.parse(date_from_certificate_string); + long difference = Math.abs(date_from_certificate.getTime() - certificate_x509.getNotAfter().getTime())/2; + long current_date_millis = offset_date.getTimeInMillis(); + offset_date.setTimeInMillis(current_date_millis + difference); + Log.d(TAG, "certificate not after = " + certificate_x509.getNotAfter()); + } catch(ParseException e) { + e.printStackTrace(); + } + + Bundle result_data = new Bundle(); + result_data.putString(REQUEST_TAG, ACTION_CHECK_CERT_VALIDITY); + try { + Log.d(TAG, "offset_date = " + offset_date.getTime().toString()); + certificate_x509.checkValidity(offset_date.getTime()); + mReceiver.send(Activity.RESULT_OK, result_data); + Log.d(TAG, "Valid certificate"); + } catch(CertificateExpiredException e) { + mReceiver.send(Activity.RESULT_CANCELED, result_data); + Log.d(TAG, "Updating certificate"); + } catch(CertificateNotYetValidException e) { + mReceiver.send(Activity.RESULT_CANCELED, result_data); + } + } + } + /** * OVPNGateway provides objects defining gateways and their options and metadata. * Each instance contains a VpnProfile for OpenVPN specific data and member @@ -439,7 +408,6 @@ public final class EIP extends IntentService { private void loadVpnProfile() { ProfileManager vpl = ProfileManager.getInstance(context); - try { if ( mName == null ) mVpnProfile = vpl.getProfiles().iterator().next(); @@ -469,48 +437,44 @@ public final class EIP extends IntentService { Collection<VpnProfile> profiles = vpl.getProfiles(); for (Iterator<VpnProfile> it = profiles.iterator(); it.hasNext(); ){ VpnProfile p = it.next(); - try { - if ( p.mName.equalsIgnoreCase( gateway.getString("host") ) ){ - it.remove(); - vpl.removeProfile(context, p); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + + if ( p.mName.equalsIgnoreCase( mName ) ) { + it.remove(); + vpl.removeProfile(context, p); } } this.createVPNProfile(); - setUniqueProfileName(vpl); vpl.addProfile(mVpnProfile); vpl.saveProfile(context, mVpnProfile); vpl.saveProfileList(context); } - + /** - * Attempts to create a unique profile name from the hostname of the gateway - * - * @param profileManager + * Create and attach the VpnProfile to our gateway object */ - private void setUniqueProfileName(ProfileManager profileManager) { - int i=0; - - String newname; + protected void createVPNProfile(){ try { - newname = mGateway.getString("host"); - while(profileManager.getProfileByName(newname)!=null) { - i++; - if(i==1) - newname = getString(R.string.converted_profile); - else - newname = getString(R.string.converted_profile_i,i); - } - - mVpnProfile.mName=newname; - } catch (JSONException e) { - // TODO Auto-generated catch block - Log.v(TAG,"Couldn't read gateway name for profile creation!"); + ConfigParser cp = new ConfigParser(); + cp.parseConfig(new StringReader(configFromEipServiceDotJson())); + cp.parseConfig(new StringReader(caSecretFromSharedPreferences())); + cp.parseConfig(new StringReader(keySecretFromSharedPreferences())); + cp.parseConfig(new StringReader(certSecretFromSharedPreferences())); + cp.parseConfig(new StringReader("remote-cert-tls server")); + cp.parseConfig(new StringReader("persist-tun")); + VpnProfile vp = cp.convertProfile(); + //vp.mAuthenticationType=VpnProfile.TYPE_STATICKEYS; + mVpnProfile = vp; + mVpnProfile.mName = mName = locationAsName(); + Log.v(TAG,"Created VPNProfile"); + } catch (ConfigParseError e) { + // FIXME We didn't get a VpnProfile! Error handling! and log level + Log.v(TAG,"Error creating VPNProfile"); + e.printStackTrace(); + } catch (IOException e) { + // FIXME We didn't get a VpnProfile! Error handling! and log level + Log.v(TAG,"Error creating VPNProfile"); e.printStackTrace(); } } @@ -520,29 +484,30 @@ public final class EIP extends IntentService { */ private String configFromEipServiceDotJson() { String parsed_configuration = ""; - - String common_options = "openvpn_configuration"; - String remote = "ip_address"; - String ports = "ports"; - String protos = "protocols"; - String capabilities = "capabilities"; + String location_key = "location"; String locations = "locations"; - - Vector<String> arg = new Vector<String>(); - Vector<Vector<String>> args = new Vector<Vector<String>>(); - + + parsed_configuration += extractCommonOptionsFromEipServiceDotJson(); + parsed_configuration += extractRemotesFromEipServiceDotJson(); + + return parsed_configuration; + } + + private String extractCommonOptionsFromEipServiceDotJson() { + String common_options = ""; try { - JSONObject openvpn_configuration = eipDefinition.getJSONObject(common_options); + String common_options_key = "openvpn_configuration"; + JSONObject openvpn_configuration = eipDefinition.getJSONObject(common_options_key); Iterator keys = openvpn_configuration.keys(); Vector<Vector<String>> value = new Vector<Vector<String>>(); while ( keys.hasNext() ){ String key = keys.next().toString(); - parsed_configuration += key + " "; + common_options += key + " "; for ( String word : openvpn_configuration.getString(key).split(" ") ) - parsed_configuration += word + " "; - parsed_configuration += System.getProperty("line.separator"); + common_options += word + " "; + common_options += System.getProperty("line.separator"); } } catch (JSONException e) { @@ -550,48 +515,44 @@ public final class EIP extends IntentService { e.printStackTrace(); } - parsed_configuration += "client" + System.getProperty("line.separator"); + common_options += "client" + System.getProperty("line.separator"); - try { + return common_options; + } + + + private String extractRemotesFromEipServiceDotJson() { + String remotes = ""; + + String remote = "ip_address"; + String remote_openvpn_keyword = "remote"; + String ports = "ports"; + String protos = "protocols"; + String capabilities = "capabilities"; + String udp = "udp"; + + try { JSONArray protocolsJSON = mGateway.getJSONObject(capabilities).getJSONArray(protos); - String remote_line = "remote"; for ( int i=0; i<protocolsJSON.length(); i++ ) { + String remote_line = remote_openvpn_keyword; remote_line += " " + mGateway.getString(remote); remote_line += " " + mGateway.getJSONObject(capabilities).getJSONArray(ports).optString(0); remote_line += " " + protocolsJSON.optString(i); - if(remote_line.endsWith("udp")) - parsed_configuration = parsed_configuration.replaceFirst(System.getProperty("line.separator") + "remote", System.getProperty("line.separator") + remote_line + System.getProperty("line.separator") + "remote"); + if(remote_line.endsWith(udp)) + remotes = remotes.replaceFirst(remote_openvpn_keyword, remote_line + System.getProperty("line.separator") + remote_openvpn_keyword); else - parsed_configuration += remote_line; - remote_line = "remote"; - parsed_configuration += System.getProperty("line.separator"); + remotes += remote_line; + remotes += System.getProperty("line.separator"); } } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } - // try { - // arg.add(location_key); - // String locationText = ""; - // locationText = eipDefinition.getJSONObject(locations).getJSONObject(mGateway.getString(location_key)).getString("name"); - // arg.add(locationText); - // Log.d(TAG, "location = " + locationText); - - // } catch (JSONException e) { - // // TODO Auto-generated catch block - // e.printStackTrace(); - // } - // args.add((Vector<String>) arg.clone()); - // options.put("location", (Vector<Vector<String>>) args.clone() ); - - // arg.clear(); - // args.clear(); - - return parsed_configuration; + Log.d(TAG, "remotes = " + remotes); + return remotes; } - private String caSecretFromSharedPreferences() { String secret_lines = ""; SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE); @@ -635,35 +596,16 @@ public final class EIP extends IntentService { return secret_lines; } + - /** - * Create and attach the VpnProfile to our gateway object - */ - protected void createVPNProfile(){ - try { - ConfigParser cp = new ConfigParser(); - Log.d(TAG, configFromEipServiceDotJson()); - Log.d(TAG, caSecretFromSharedPreferences()); - Log.d(TAG, keySecretFromSharedPreferences()); - Log.d(TAG, certSecretFromSharedPreferences()); - cp.parseConfig(new StringReader(configFromEipServiceDotJson())); - cp.parseConfig(new StringReader(caSecretFromSharedPreferences())); - cp.parseConfig(new StringReader(keySecretFromSharedPreferences())); - cp.parseConfig(new StringReader(certSecretFromSharedPreferences())); - VpnProfile vp = cp.convertProfile(); - //vp.mAuthenticationType=VpnProfile.TYPE_STATICKEYS; - mVpnProfile = vp; - Log.v(TAG,"Created VPNProfile"); - } catch (ConfigParseError e) { - // FIXME We didn't get a VpnProfile! Error handling! and log level - Log.v(TAG,"Error creating VPNProfile"); - e.printStackTrace(); - } catch (IOException e) { - // FIXME We didn't get a VpnProfile! Error handling! and log level - Log.v(TAG,"Error creating VPNProfile"); - e.printStackTrace(); - } + public String locationAsName() { + try { + return eipDefinition.getJSONObject("locations").getJSONObject(mGateway.getString("location")).getString("name"); + } catch (JSONException e) { + Log.v(TAG,"Couldn't read gateway name for profile creation! Returning original name = " + mName); + e.printStackTrace(); + return (mName != null) ? mName : ""; } + } } - } diff --git a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java index 299d89a4..c8a28c0a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java @@ -1,6 +1,10 @@ package se.leap.bitmaskclient; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.ProviderAPIResultReceiver; +import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver; +import se.leap.bitmaskclient.Dashboard; + import de.blinkt.openvpn.activities.LogWindow; import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; @@ -21,6 +25,7 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CompoundButton; +import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.Switch; import android.widget.TextView; @@ -35,12 +40,6 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe private View eipDetail; private TextView eipStatus; - private boolean eipAutoSwitched = true; - - private boolean mEipStartPending = false; - - private boolean set_switch_off = false; - private static EIPReceiver mEIPReceiver; @@ -50,29 +49,19 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false); - + eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false); eipDetail = ((RelativeLayout) eipFragment.findViewById(R.id.eipDetail)); eipDetail.setVisibility(View.VISIBLE); View eipSettings = eipFragment.findViewById(R.id.eipSettings); eipSettings.setVisibility(View.GONE); // FIXME too! - if (mEipStartPending) - eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); + if (EIP.mIsStarting) + eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); eipStatus = (TextView) eipFragment.findViewById(R.id.eipStatus); eipSwitch = (Switch) eipFragment.findViewById(R.id.eipSwitch); - - - eipSwitch.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - eipAutoSwitched = false; - return false; - } - }); eipSwitch.setOnCheckedChangeListener(this); if(getArguments() != null && getArguments().containsKey(START_ON_BOOT) && getArguments().getBoolean(START_ON_BOOT)) @@ -88,7 +77,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe mEIPReceiver = new EIPReceiver(new Handler()); if (savedInstanceState != null) - mEipStartPending = savedInstanceState.getBoolean(IS_EIP_PENDING); + EIP.mIsStarting = savedInstanceState.getBoolean(IS_EIP_PENDING); } @Override @@ -96,15 +85,9 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe super.onResume(); VpnStatus.addStateListener(this); - if(set_switch_off) { - eipSwitch.setChecked(false); - set_switch_off = false; - } + + eipCommand(EIP.ACTION_CHECK_CERT_VALIDITY); } - - protected void setSwitchOff(boolean value) { - set_switch_off = value; - } @Override public void onPause() { @@ -116,7 +99,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - outState.putBoolean(IS_EIP_PENDING, mEipStartPending); + outState.putBoolean(IS_EIP_PENDING, EIP.mIsStarting); } protected void saveEipStatus() { @@ -127,68 +110,101 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe } if(getActivity() != null) - getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).edit().putBoolean(Dashboard.START_ON_BOOT, eip_is_on).commit(); + Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, eip_is_on).commit(); } - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - Log.d("bitmask", "onCheckChanged"); - if (buttonView.equals(eipSwitch) && !eipAutoSwitched){ - boolean allowed_anon = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).getBoolean(EIP.ALLOWED_ANON, false); - String certificate = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).getString(EIP.CERTIFICATE, ""); - if(allowed_anon || !certificate.isEmpty()) { - if (isChecked){ - startEipFromScratch(); - } else { - if (mEipStartPending){ - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); - alertBuilder.setTitle(getResources().getString(R.string.eip_cancel_connect_title)); - alertBuilder - .setMessage(getResources().getString(R.string.eip_cancel_connect_text)) - .setPositiveButton(getResources().getString(R.string.eip_cancel_connect_cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - eipCommand(EIP.ACTION_STOP_EIP); - mEipStartPending = false; - } - }) - .setNegativeButton(getResources().getString(R.string.eip_cancel_connect_false), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - eipAutoSwitched = true; - eipSwitch.setChecked(true); - eipAutoSwitched = false; - } - }) - .show(); - } else { - eipCommand(EIP.ACTION_STOP_EIP); - } - } - } - else { - Dashboard dashboard = (Dashboard)getActivity(); - Bundle waiting_on_login = new Bundle(); - waiting_on_login.putBoolean(IS_EIP_PENDING, true); - dashboard.logInDialog(getActivity().getCurrentFocus(), waiting_on_login); - } - } - else { - if(!eipSwitch.isChecked()) - eipStatus.setText(R.string.state_noprocess); - } - eipAutoSwitched = true; - saveEipStatus(); + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (buttonView.equals(eipSwitch)){ + handleSwitch(isChecked); } + } + + private void handleSwitch(boolean isChecked) { + if(isChecked) + handleSwitchOn(); + else + handleSwitchOff(); + saveEipStatus(); + } + + private void handleSwitchOn() { + if(canStartEIP()) + startEipFromScratch(); + else if(canLogInToStartEIP()) { + Log.d(TAG, "Can Log In to start EIP"); + Dashboard dashboard = (Dashboard) getActivity(); + dashboard.logInDialog(Bundle.EMPTY); + } + } + + private boolean canStartEIP() { + boolean certificateExists = !Dashboard.preferences.getString(EIP.CERTIFICATE, "").isEmpty(); + boolean isAllowedAnon = Dashboard.preferences.getBoolean(EIP.ALLOWED_ANON, false); + return (isAllowedAnon || certificateExists) && !EIP.mIsStarting && !EIP.isConnected(); + } + + private boolean canLogInToStartEIP() { + boolean isAllowedRegistered = Dashboard.preferences.getBoolean(EIP.ALLOWED_REGISTERED, false); + boolean isLoggedIn = Dashboard.preferences.getBoolean(EIP.AUTHED_EIP, false); + Log.d(TAG, "Allow registered? " + isAllowedRegistered); + Log.d(TAG, "Is logged in? " + isLoggedIn); + return isAllowedRegistered && !isLoggedIn && !EIP.mIsStarting && !EIP.isConnected(); + } + + private void handleSwitchOff() { + if(EIP.mIsStarting) { + askPendingStartCancellation(); + } else if(EIP.isConnected()) { + Log.d(TAG, "Stopping EIP"); + stopEIP(); + } + } + + private void askPendingStartCancellation() { + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); + alertBuilder.setTitle(getResources().getString(R.string.eip_cancel_connect_title)) + .setMessage(getResources().getString(R.string.eip_cancel_connect_text)) + .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + stopEIP(); + } + }) + .setNegativeButton(getResources().getString(R.string.no), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Log.d(TAG, "askPendingStartCancellation checks the switch to true"); + eipSwitch.setChecked(true); + } + }) + .show(); + } public void startEipFromScratch() { - mEipStartPending = true; + EIP.mIsStarting = true; eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); - ((TextView) eipFragment.findViewById(R.id.eipStatus)).setText(R.string.eip_status_start_pending); - eipSwitch.setChecked(true); - saveEipStatus(); + String status = getResources().getString(R.string.eip_status_start_pending); + setEipStatus(status); + + if(!eipSwitch.isChecked()) { + Log.d(TAG, "startEipFromScratch checks the switch to true"); + eipSwitch.setChecked(true); + saveEipStatus(); + } eipCommand(EIP.ACTION_START_EIP); } + + private void stopEIP() { + EIP.mIsStarting = false; + View eipProgressBar = getActivity().findViewById(R.id.eipProgress); + if(eipProgressBar != null) + eipProgressBar.setVisibility(View.GONE); + + String status = getResources().getString(R.string.eip_state_not_connected); + setEipStatus(status); + eipCommand(EIP.ACTION_STOP_EIP); + } /** * Send a command to EIP @@ -198,49 +214,104 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe */ private void eipCommand(String action){ // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? - Intent vpnIntent = new Intent(action); - vpnIntent.putExtra(EIP.RECEIVER_TAG, mEIPReceiver); - getActivity().startService(vpnIntent); + Intent vpn_intent = new Intent(getActivity().getApplicationContext(), EIP.class); + vpn_intent.setAction(action); + vpn_intent.putExtra(EIP.RECEIVER_TAG, mEIPReceiver); + getActivity().startService(vpn_intent); } - @Override - public void updateState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) { - // Note: "states" are not organized anywhere...collected state strings: - // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT ) - getActivity().runOnUiThread(new Runnable() { - - @Override - public void run() { - if (eipStatus != null) { - boolean switchState = true; - String statusMessage = ""; - String prefix = getString(localizedResId); - if (level == ConnectionStatus.LEVEL_CONNECTED){ - statusMessage = getString(R.string.eip_state_connected); - getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); - mEipStartPending = false; - } else if ( level == ConnectionStatus.LEVEL_NONETWORK || level == ConnectionStatus.LEVEL_NOTCONNECTED || level == ConnectionStatus.LEVEL_AUTH_FAILED) { - statusMessage = getString(R.string.eip_state_not_connected); - if(getActivity() != null && getActivity().findViewById(R.id.eipProgress) != null) - getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); - mEipStartPending = false; - switchState = false; - } else if (level == ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED) { - if(state.equals("AUTH") || state.equals("GET_CONFIG")) - statusMessage = prefix + " " + logmessage; - } else if (level == ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET) { - statusMessage = prefix + " " + logmessage; - } - - eipAutoSwitched = true; - eipSwitch.setChecked(switchState); - eipAutoSwitched = false; - eipStatus.setText(statusMessage); - } - } + @Override + public void updateState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) { + boolean isNewLevel = EIP.lastConnectionStatusLevel != level; + boolean justDecidedOnDisconnect = EIP.lastConnectionStatusLevel == ConnectionStatus.UNKNOWN_LEVEL; + Log.d(TAG, "update state with level " + level); + if(!justDecidedOnDisconnect && (isNewLevel || level == ConnectionStatus.LEVEL_CONNECTED)) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + EIP.lastConnectionStatusLevel = level; + handleNewState(state, logmessage, localizedResId, level); + } }); + } else if(justDecidedOnDisconnect && level == ConnectionStatus.LEVEL_CONNECTED) { + EIP.lastConnectionStatusLevel = ConnectionStatus.LEVEL_NOTCONNECTED; + updateState(state, logmessage, localizedResId, level); + } + } + + private void handleNewState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) { + if (level == ConnectionStatus.LEVEL_CONNECTED) + setConnectedUI(); + else if (isDisconnectedLevel(level) && !EIP.mIsStarting) + setDisconnectedUI(); + else if (level == ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET) + setNoServerReplyUI(localizedResId, logmessage); + else if (level == ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED) + setServerReplyUI(state, localizedResId, logmessage); + } + + private boolean isDisconnectedLevel(final ConnectionStatus level) { + return level == ConnectionStatus.LEVEL_NONETWORK || level == ConnectionStatus.LEVEL_NOTCONNECTED || level == ConnectionStatus.LEVEL_AUTH_FAILED; + } + + private void setConnectedUI() { + hideProgressBar(); + Log.d(TAG, "mIsDisconnecting = false in setConnectedUI"); + EIP.mIsStarting = false; //TODO This should be done in the onReceiveResult from START_EIP command, but right now LaunchVPN isn't notifying anybody the resultcode of the request so we need to listen the states with this listener. + EIP.mIsDisconnecting = false; //TODO See comment above + String status = getString(R.string.eip_state_connected); + setEipStatus(status); + adjustSwitch(); + } + + private void setDisconnectedUI(){ + hideProgressBar(); + EIP.mIsStarting = false; //TODO See comment in setConnectedUI() + Log.d(TAG, "mIsDisconnecting = false in setDisconnectedUI"); + EIP.mIsDisconnecting = false; //TODO See comment in setConnectedUI() + + String status = getString(R.string.eip_state_not_connected); + setEipStatus(status); + adjustSwitch(); + } + + private void adjustSwitch() { + if(EIP.isConnected()) { + if(!eipSwitch.isChecked()) { + eipSwitch.setChecked(true); + } + } else { + if(eipSwitch.isChecked()) { + eipSwitch.setChecked(false); + } } + } + + private void setNoServerReplyUI(int localizedResId, String logmessage) { + if(eipStatus != null) { + String prefix = getString(localizedResId); + setEipStatus(prefix + " " + logmessage); + } + } + + private void setServerReplyUI(String state, int localizedResId, String logmessage) { + if(eipStatus != null) + if(state.equals("AUTH") || state.equals("GET_CONFIG")) { + String prefix = getString(localizedResId); + setEipStatus(prefix + " " + logmessage); + } + } + protected void setEipStatus(String status) { + if(eipStatus == null) + eipStatus = (TextView) getActivity().findViewById(R.id.eipStatus); + eipStatus.setText(status); + } + + private void hideProgressBar() { + if(getActivity() != null && getActivity().findViewById(R.id.eipProgress) != null) + getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); + } /** * Inner class for handling messages related to EIP status and control requests @@ -256,7 +327,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe @Override protected void onReceiveResult(int resultCode, Bundle resultData) { super.onReceiveResult(resultCode, resultData); - + String request = resultData.getString(EIP.REQUEST_TAG); boolean checked = false; @@ -272,8 +343,10 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe } else if (request == EIP.ACTION_START_EIP) { switch (resultCode){ case Activity.RESULT_OK: + Log.d(TAG, "Action start eip = Result OK"); checked = true; eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); + EIP.mIsStarting = false; break; case Activity.RESULT_CANCELED: checked = false; @@ -298,11 +371,31 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe checked = false; break; } + } else if (request == EIP.ACTION_CHECK_CERT_VALIDITY) { + checked = eipSwitch.isChecked(); + + switch (resultCode) { + case Activity.RESULT_OK: + break; + case Activity.RESULT_CANCELED: + Dashboard dashboard = (Dashboard) getActivity(); + + dashboard.setProgressBarVisibility(ProgressBar.VISIBLE); + String status = getResources().getString(R.string.updating_certificate_message); + setEipStatus(status); + + Intent provider_API_command = new Intent(getActivity(), ProviderAPI.class); + if(dashboard.providerAPI_result_receiver == null) { + dashboard.providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + dashboard.providerAPI_result_receiver.setReceiver(dashboard); + } + + provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, dashboard.providerAPI_result_receiver); + getActivity().startService(provider_API_command); + break; + } } - - eipAutoSwitched = true; - eipSwitch.setChecked(checked); - eipAutoSwitched = false; } } @@ -317,6 +410,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe public void checkEipSwitch(boolean checked) { eipSwitch.setChecked(checked); - onCheckedChanged(eipSwitch, checked); + // Log.d(TAG, "checkEipSwitch"); + // onCheckedChanged(eipSwitch, checked); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java b/app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java deleted file mode 100644 index 8793cf36..00000000 --- a/app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java +++ /dev/null @@ -1,17 +0,0 @@ -package se.leap.bitmaskclient; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.util.Log; - - -public class EipStatusReceiver extends BroadcastReceiver { - - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals("de.blinkt.openvpn.VPN_STATUS")) { - context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Context.MODE_PRIVATE).edit().putString(EIP.STATUS, intent.getStringExtra("status")).commit(); - } - } -} |