summaryrefslogtreecommitdiff
path: root/app/src/main/java/se
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/se')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/AboutActivity.java5
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java13
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Dashboard.java237
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java3
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EIP.java524
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java466
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java3
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/LogInDialog.java53
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java4
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Provider.java12
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java4
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderListFragment.java11
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/SessionDialogInterface.java2
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java50
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/Constants.java47
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EIP.java255
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java138
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java156
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java46
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java (renamed from app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java)6
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java (renamed from app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java)7
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java60
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java (renamed from app/src/main/java/se/leap/bitmaskclient/VpnConfigGenerator.java)17
23 files changed, 1101 insertions, 1018 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/AboutActivity.java b/app/src/main/java/se/leap/bitmaskclient/AboutActivity.java
index 6d025422..6c4e517b 100644
--- a/app/src/main/java/se/leap/bitmaskclient/AboutActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/AboutActivity.java
@@ -1,15 +1,10 @@
package se.leap.bitmaskclient;
import android.app.Activity;
-import android.app.Fragment;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
import android.widget.TextView;
-import se.leap.bitmaskclient.R;
public class AboutActivity extends Activity {
diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java
index c95d0c8b..c0f0b0c3 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java
@@ -16,11 +16,15 @@
*/
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.lang.IllegalArgumentException;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
@@ -33,13 +37,6 @@ import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Base64;
-
/**
* Stores constants, and implements auxiliary methods used across all LEAP Android classes.
*
diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
index 364a79af..8143d8d6 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
@@ -14,17 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- package se.leap.bitmaskclient;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver;
-import se.leap.bitmaskclient.FragmentManagerEnhanced;
-import se.leap.bitmaskclient.SignUpDialog;
-
-import de.blinkt.openvpn.activities.LogWindow;
+package se.leap.bitmaskclient;
import android.app.Activity;
import android.app.AlertDialog;
@@ -41,11 +31,16 @@ import android.os.ResultReceiver;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
-import android.widget.Toast;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import de.blinkt.openvpn.activities.LogWindow;
+import se.leap.bitmaskclient.eip.Constants;
+import se.leap.bitmaskclient.eip.EIP;
+import se.leap.bitmaskclient.eip.EipStatus;
/**
* The main user facing Activity of LEAP Android, consisting of status, controls,
@@ -54,11 +49,12 @@ import android.widget.Toast;
* @author Sean Leonard <meanderingcode@aetherislands.net>
* @author parmegv
*/
-public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface, SignUpDialog.SignUpDialogInterface, Receiver {
+public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface, SignUpDialog.SignUpDialogInterface, ProviderAPIResultReceiver.Receiver {
protected static final int CONFIGURE_LEAP = 0;
protected static final int SWITCH_PROVIDER = 1;
+ final public static String TAG = Dashboard.class.getSimpleName();
final public static String SHARED_PREFERENCES = "LEAPPreferences";
final public static String ACTION_QUIT = "quit";
public static final String REQUEST_CODE = "request_code";
@@ -66,21 +62,17 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
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";
- final public static String TAG = Dashboard.class.getSimpleName();
-
- private EipServiceFragment eipFragment;
- private ProgressBar mProgressBar;
- private TextView eipStatus;
- private static Context app;
- protected static SharedPreferences preferences;
- private static Provider provider;
-
- private boolean authed_eip = false;
+ private static Context app;
+ protected static SharedPreferences preferences;
+ private FragmentManagerEnhanced fragment_manager;
+ private ProgressBar mProgressBar;
+ private TextView status_message;
public ProviderAPIResultReceiver providerAPI_result_receiver;
- private FragmentManagerEnhanced fragment_manager;
+ private static boolean authed_eip;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -95,32 +87,33 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
fragment_manager = new FragmentManagerEnhanced(getFragmentManager());
handleVersion();
- authed_eip = preferences.getBoolean(EIP.AUTHED_EIP, false);
- if (preferences.getString(Provider.KEY, "").isEmpty())
- startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP);
- else
- buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false));
+ boolean provider_configured = preferences.getString(Constants.KEY, "").isEmpty();
+ if (provider_configured)
+ startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP);
+ else
+ buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false));
}
private void handleVersion() {
try {
int versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
int lastDetectedVersion = preferences.getInt(APP_VERSION, 0);
- preferences.edit().putInt(APP_VERSION, versionCode);
+ preferences.edit().putInt(APP_VERSION, versionCode).apply();
Log.d("Dashboard", "detected version code: " + versionCode);
Log.d("Dashboard", "last detected version code: " + lastDetectedVersion);
switch(versionCode) {
case 91: // 0.6.0 without Bug #5999
case 101: // 0.8.0
- if(!preferences.getString(EIP.KEY, "").isEmpty()) {
+ if(!preferences.getString(Constants.KEY, "").isEmpty()) {
Intent rebuildVpnProfiles = new Intent(getApplicationContext(), EIP.class);
- rebuildVpnProfiles.setAction(EIP.ACTION_REBUILD_PROFILES);
+ rebuildVpnProfiles.setAction(Constants.ACTION_UPDATE_EIP_SERVICE);
startService(rebuildVpnProfiles);
}
break;
}
} catch (NameNotFoundException e) {
+ Log.d(TAG, "Handle version didn't find any " + getPackageName() + " package");
}
}
@@ -134,30 +127,28 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
super.onPause();
}
- @Override
- protected void onActivityResult(int requestCode, int resultCode, final Intent data){
- if ( requestCode == CONFIGURE_LEAP || requestCode == SWITCH_PROVIDER) {
- // It should be equivalent: if ( (requestCode == CONFIGURE_LEAP) || (data!= null && data.hasExtra(STOP_FIRST))) {
- if ( resultCode == RESULT_OK ){
- preferences.edit().putInt(EIP.PARSED_SERIAL, 0).commit();
- preferences.edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit();
-
- Intent updateEIP = new Intent(getApplicationContext(), EIP.class);
- updateEIP.setAction(EIP.ACTION_UPDATE_EIP_SERVICE);
- startService(updateEIP);
-
- buildDashboard(false);
- invalidateOptionsMenu();
- if(data != null && data.hasExtra(LogInDialog.TAG)) {
- View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0);
- logInDialog(Bundle.EMPTY);
- }
- } else if(resultCode == RESULT_CANCELED && (data == null || data.hasExtra(ACTION_QUIT))) {
- finish();
- } else
- configErrorDialog();
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data){
+ Log.d(TAG, "onActivityResult: requestCode = " + requestCode);
+ if ( requestCode == CONFIGURE_LEAP || requestCode == SWITCH_PROVIDER) {
+ // It should be equivalent: if ( (requestCode == CONFIGURE_LEAP) || (data!= null && data.hasExtra(STOP_FIRST))) {
+ if ( resultCode == RESULT_OK ){
+ preferences.edit().putInt(Constants.PARSED_SERIAL, 0).apply();
+ preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply();
+ updateEipService();
+ buildDashboard(false);
+ invalidateOptionsMenu();
+ if(data != null && data.hasExtra(LogInDialog.TAG)) {
+ logInDialog(Bundle.EMPTY);
}
+ } else if(resultCode == RESULT_CANCELED && (data == null || data.hasExtra(ACTION_QUIT))) {
+ finish();
+ } else
+ configErrorDialog();
+ } else if(requestCode == EIP.DISCONNECT) {
+ EipStatus.getInstance().setConnectedOrDisconnected();
}
+ }
/**
* Dialog shown when encountering a configuration error. Such errors require
@@ -178,7 +169,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
.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).commit();
+ preferences.edit().remove(Provider.KEY).apply();
finish();
}
})
@@ -190,7 +181,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
* service dependent UI elements to include.
*/
private void buildDashboard(boolean hide_and_turn_on_eip) {
- provider = Provider.getInstance();
+ Provider provider = Provider.getInstance();
provider.init( this );
setContentView(R.layout.client_dashboard);
@@ -199,21 +190,27 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
providerNameTV.setText(provider.getDomain());
providerNameTV.setTextSize(28);
- mProgressBar = (ProgressBar) findViewById(R.id.eipProgress);
+ mProgressBar = (ProgressBar) findViewById(R.id.eipProgress);
if ( provider.hasEIP()){
- eipFragment = new EipServiceFragment();
- if (hide_and_turn_on_eip) {
- preferences.edit().remove(Dashboard.START_ON_BOOT).commit();
- Bundle arguments = new Bundle();
- arguments.putBoolean(EipServiceFragment.START_ON_BOOT, true);
- eipFragment.setArguments(arguments);
- }
- fragment_manager.replace(R.id.servicesCollection, eipFragment, EipServiceFragment.TAG);
- if (hide_and_turn_on_eip) {
- onBackPressed();
- }
+ EipServiceFragment eip_fragment = (EipServiceFragment) fragment_manager.findFragmentByTag(EipServiceFragment.TAG);
+ if(eip_fragment == null)
+ eip_fragment = new EipServiceFragment();
+
+ if (hide_and_turn_on_eip) {
+ preferences.edit().remove(Dashboard.START_ON_BOOT).apply();
+ Bundle arguments = new Bundle();
+ arguments.putBoolean(EipServiceFragment.START_ON_BOOT, true);
+ eip_fragment.setArguments(arguments);
+ }
+
+ fragment_manager.removePreviousFragment(EipServiceFragment.TAG);
+ fragment_manager.replace(R.id.servicesCollection, eip_fragment, EipServiceFragment.TAG);
+
+ if (hide_and_turn_on_eip) {
+ onBackPressed();
+ }
}
}
@@ -222,12 +219,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
JSONObject provider_json;
try {
String provider_json_string = preferences.getString(Provider.KEY, "");
- if(provider_json_string.isEmpty() == false) {
+ 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(EIP.ALLOWED_REGISTERED, allow_registered_eip);
+ preferences.edit().putBoolean(Constants.ALLOWED_REGISTERED, allow_registered_eip).apply();
if(allow_registered_eip) {
if(authed_eip) {
@@ -268,12 +265,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
return true;
case R.id.switch_provider:
if (Provider.getInstance().hasEIP()){
- if (preferences.getBoolean(EIP.AUTHED_EIP, false)){
+ if (preferences.getBoolean(Constants.AUTHED_EIP, false)){
logOut();
}
eipStop();
}
- preferences.edit().clear().commit();
+ preferences.edit().clear().apply();
startActivityForResult(new Intent(this,ConfigurationWizard.class), SWITCH_PROVIDER);
return true;
case R.id.login_button:
@@ -293,7 +290,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
private Intent prepareProviderAPICommand() {
mProgressBar = (ProgressBar) findViewById(R.id.eipProgress);
- eipStatus = (TextView) findViewById(R.id.eipStatus);
+ status_message = (TextView) findViewById(R.id.status_message);
providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
providerAPI_result_receiver.setReceiver(this);
@@ -327,20 +324,15 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
parameters.putString(SessionDialogInterface.PASSWORD, password);
mProgressBar.setVisibility(ProgressBar.VISIBLE);
- eipStatus.setText(R.string.authenticating_message);
+ status_message.setText(R.string.authenticating_message);
provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters);
provider_API_command.setAction(ProviderAPI.SRP_AUTH);
startService(provider_API_command);
}
- public void cancelAuthedEipOn() {
- EipServiceFragment eipFragment = (EipServiceFragment) getFragmentManager().findFragmentByTag(EipServiceFragment.TAG);
- eipFragment.checkEipSwitch(false);
- }
-
public void cancelLoginOrSignup() {
- hideProgressBar();
+ EipStatus.getInstance().setConnectedOrDisconnected();
}
/**
@@ -351,8 +343,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
if(mProgressBar == null) mProgressBar = (ProgressBar) findViewById(R.id.eipProgress);
mProgressBar.setVisibility(ProgressBar.VISIBLE);
- if(eipStatus == null) eipStatus = (TextView) findViewById(R.id.eipStatus);
- eipStatus.setText(R.string.logout_message);
+ if(status_message == null) status_message = (TextView) findViewById(R.id.status_message);
+ status_message.setText(R.string.logout_message);
provider_API_command.setAction(ProviderAPI.LOG_OUT);
startService(provider_API_command);
@@ -382,7 +374,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
parameters.putString(SessionDialogInterface.PASSWORD, password);
mProgressBar.setVisibility(ProgressBar.VISIBLE);
- eipStatus.setText(R.string.signingup_message);
+ status_message.setText(R.string.signingup_message);
provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters);
provider_API_command.setAction(ProviderAPI.SRP_REGISTER);
@@ -410,6 +402,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
+ Log.d(TAG, "onReceiveResult");
if(resultCode == ProviderAPI.SRP_REGISTRATION_SUCCESSFUL) {
String username = resultData.getString(SessionDialogInterface.USERNAME);
String password = resultData.getString(SessionDialogInterface.PASSWORD);
@@ -426,7 +419,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
invalidateOptionsMenu();
authed_eip = true;
- preferences.edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit();
+ preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply();
downloadAuthedUserCertificate();
} else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_FAILED) {
@@ -441,7 +434,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
invalidateOptionsMenu();
authed_eip = false;
- preferences.edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit();
+ preferences.edit().putBoolean(Constants.AUTHED_EIP, authed_eip).apply();
} else if(resultCode == ProviderAPI.LOGOUT_FAILED) {
changeStatusMessage(resultCode);
@@ -453,22 +446,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
hideProgressBar();
setResult(RESULT_OK);
- Intent updateEIP = new Intent(getApplicationContext(), EIP.class);
- ResultReceiver eip_receiver = new ResultReceiver(new Handler()){
- protected void onReceiveResult(int resultCode, Bundle resultData){
- super.onReceiveResult(resultCode, resultData);
- String request = resultData.getString(EIP.REQUEST_TAG);
- if (resultCode == Activity.RESULT_OK){
- if(authed_eip)
- eipStart();
- else
- eipStatus.setText("Certificate updated");
- }
- }
- };
- updateEIP.putExtra(EIP.RECEIVER_TAG, eip_receiver);
- updateEIP.setAction(EIP.ACTION_UPDATE_EIP_SERVICE);
- startService(updateEIP);
+
+ updateEipService();
} else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
changeStatusMessage(resultCode);
hideProgressBar();
@@ -476,23 +455,41 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
}
}
+ private void updateEipService() {
+ Intent updateEIP = new Intent(getApplicationContext(), EIP.class);
+ updateEIP.setAction(Constants.ACTION_UPDATE_EIP_SERVICE);
+ ResultReceiver receiver = new ResultReceiver(new Handler()) {
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ String request = resultData.getString(Constants.REQUEST_TAG);
+ if(request.equalsIgnoreCase(Constants.ACTION_UPDATE_EIP_SERVICE)) {
+ if(resultCode == Activity.RESULT_OK) {
+ if(authed_eip)
+ eipStart();
+ }
+ }
+ }
+ };
+ updateEIP.putExtra(Constants.RECEIVER_TAG, receiver);
+ startService(updateEIP);
+ }
+
private void changeStatusMessage(final int previous_result_code) {
// TODO Auto-generated method stub
ResultReceiver eip_status_receiver = new ResultReceiver(new Handler()){
protected void onReceiveResult(int resultCode, Bundle resultData){
super.onReceiveResult(resultCode, resultData);
- String request = resultData.getString(EIP.REQUEST_TAG);
- if(eipStatus == null) eipStatus = (TextView) findViewById(R.id.eipStatus);
- if (request.equalsIgnoreCase(EIP.ACTION_IS_EIP_RUNNING)){
+ String request = resultData.getString(Constants.REQUEST_TAG);
+ if(status_message == null) status_message = (TextView) findViewById(R.id.status_message);
+ if (request.equalsIgnoreCase(Constants.ACTION_IS_EIP_RUNNING)){
if (resultCode == Activity.RESULT_OK){
switch(previous_result_code){
- case ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL: eipStatus.setText(R.string.succesful_authentication_message); break;
- case ProviderAPI.SRP_AUTHENTICATION_FAILED: eipStatus.setText(R.string.authentication_failed_message); break;
- case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.authed_secured_status); break;
- case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.incorrectly_downloaded_certificate_message); break;
- case ProviderAPI.LOGOUT_SUCCESSFUL: eipStatus.setText(R.string.logged_out_message); break;
- case ProviderAPI.LOGOUT_FAILED: eipStatus.setText(R.string.log_out_failed_message); break;
+ case ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL: status_message.setText(R.string.succesful_authentication_message); break;
+ case ProviderAPI.SRP_AUTHENTICATION_FAILED: status_message.setText(R.string.authentication_failed_message); break;
+ case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: status_message.setText(R.string.authed_secured_status); break;
+ case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: status_message.setText(R.string.incorrectly_downloaded_certificate_message); break;
+ case ProviderAPI.LOGOUT_SUCCESSFUL: status_message.setText(R.string.logged_out_message); break;
+ case ProviderAPI.LOGOUT_FAILED: status_message.setText(R.string.log_out_failed_message); break;
}
}
@@ -500,13 +497,13 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
switch(previous_result_code){
- case ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL: eipStatus.setText(R.string.succesful_authentication_message); break;
- case ProviderAPI.SRP_AUTHENTICATION_FAILED: eipStatus.setText(R.string.authentication_failed_message); break;
- case ProviderAPI.SRP_REGISTRATION_FAILED: eipStatus.setText(R.string.registration_failed_message); break;
+ case ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL: status_message.setText(R.string.succesful_authentication_message); break;
+ case ProviderAPI.SRP_AUTHENTICATION_FAILED: status_message.setText(R.string.authentication_failed_message); break;
+ case ProviderAPI.SRP_REGISTRATION_FAILED: status_message.setText(R.string.registration_failed_message); break;
case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: break;
- case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.incorrectly_downloaded_certificate_message); break;
- case ProviderAPI.LOGOUT_SUCCESSFUL: eipStatus.setText(R.string.logged_out_message); break;
- case ProviderAPI.LOGOUT_FAILED: eipStatus.setText(R.string.log_out_failed_message); break;
+ case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: status_message.setText(R.string.incorrectly_downloaded_certificate_message); break;
+ case ProviderAPI.LOGOUT_SUCCESSFUL: status_message.setText(R.string.logged_out_message); break;
+ case ProviderAPI.LOGOUT_FAILED: status_message.setText(R.string.log_out_failed_message); break;
}
}
}
@@ -544,8 +541,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
private void eipIsRunning(ResultReceiver eip_receiver){
// TODO validate "action"...how do we get the list of intent-filters for a class via Android API?
Intent eip_intent = new Intent(this, EIP.class);
- eip_intent.setAction(EIP.ACTION_IS_EIP_RUNNING);
- eip_intent.putExtra(EIP.RECEIVER_TAG, eip_receiver);
+ eip_intent.setAction(Constants.ACTION_IS_EIP_RUNNING);
+ eip_intent.putExtra(Constants.RECEIVER_TAG, eip_receiver);
startService(eip_intent);
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java
index f78002b0..a44253c6 100644
--- a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java
@@ -16,9 +16,6 @@
*/
package se.leap.bitmaskclient;
-import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.NewProviderDialog.NewProviderDialogInterface;
-import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java
deleted file mode 100644
index 2f06def3..00000000
--- a/app/src/main/java/se/leap/bitmaskclient/EIP.java
+++ /dev/null
@@ -1,524 +0,0 @@
-/**
- * Copyright (c) 2013 LEAP Encryption Access Project and contributers
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package se.leap.bitmaskclient;
-
-import android.app.Activity;
-import android.app.IntentService;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-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;
-import de.blinkt.openvpn.core.ConfigParser.ConfigParseError;
-import de.blinkt.openvpn.core.ProfileManager;
-import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
-import java.io.IOException;
-import java.io.StringReader;
-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
- * Internet Proxy connection. Connections are started, stopped, and queried through
- * this IntentService.
- * Contains logic for parsing eip-service.json from the provider, configuring and selecting
- * gateways, and controlling {@link de.blinkt.openvpn.core.OpenVPNService} connections.
- *
- * @author Sean Leonard <meanderingcode@aetherislands.net>
- * @author Parménides GV <parmegv@sdf.org>
- */
-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 ACTION_REBUILD_PROFILES = "se.leap.bitmaskclient.REBUILD_PROFILES";
- 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";
- public final static String PARSED_SERIAL = "eip_parsed_serial";
- public final static String SERVICE_API_PATH = "config/eip-service.json";
- public final static String RECEIVER_TAG = "receiverTag";
- public final static String REQUEST_TAG = "requestTag";
- public final static String TAG = EIP.class.getSimpleName();
- private static SharedPreferences preferences;
-
- private static Context context;
- private static ResultReceiver mReceiver;
- private static boolean mBound = false;
-
- 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 static SimpleDateFormat certificate_date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US);
- public EIP(){
- super("LEAPEIP");
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- context = getApplicationContext();
-
- preferences = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE);
- }
-
- @Override
- public void onDestroy() {
-
- mBound = false;
-
- super.onDestroy();
- }
-
-
- @Override
- protected void onHandleIntent(Intent intent) {
- String action = intent.getAction();
- mReceiver = intent.getParcelableExtra(RECEIVER_TAG);
-
- if ( action == ACTION_START_EIP )
- startEIP();
- else if ( action == ACTION_STOP_EIP )
- stopEIP();
- else if ( action == ACTION_IS_EIP_RUNNING )
- isRunning();
- else if ( action == ACTION_UPDATE_EIP_SERVICE )
- updateEIPService();
- else if ( action == ACTION_CHECK_CERT_VALIDITY )
- checkCertValidity();
- else if ( action == ACTION_REBUILD_PROFILES )
- updateGateways();
- }
-
- /**
- * Initiates an EIP connection by selecting a gateway and preparing and sending an
- * Intent to {@link se.leap.openvpn.LaunchVPN}.
- * It also sets up early routes.
- */
- private void startEIP() {
- earlyRoutes();
- activeGateway = selectGateway();
-
- if(activeGateway != null && activeGateway.mVpnProfile != null) {
- mReceiver = EipServiceFragment.getReceiver();
- launchActiveGateway();
- }
- }
-
- /**
- * Early routes are routes that block traffic until a new
- * 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);
- }
-
- /**
- * Choose a gateway to connect to based on timezone from system locale data
- *
- * @return The gateway to connect to
- */
- private OVPNGateway selectGateway() {
- String closest_location = closestGateway();
- String chosen_host = chooseHost(closest_location);
-
- return new OVPNGateway(chosen_host);
- }
-
- private String closestGateway() {
- TreeMap<Integer, Set<String>> offsets = calculateOffsets();
- return offsets.isEmpty() ? "" : offsets.firstEntry().getValue().iterator().next();
- }
-
- private TreeMap<Integer, Set<String>> calculateOffsets() {
- TreeMap<Integer, Set<String>> offsets = new TreeMap<Integer, Set<String>>();
-
- int localOffset = Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000;
-
- JSONObject locations = availableLocations();
- Iterator<String> locations_names = locations.keys();
- while(locations_names.hasNext()) {
- try {
- String location_name = locations_names.next();
- JSONObject location = locations.getJSONObject(location_name);
-
- int dist = timezoneDistance(localOffset, location.optInt("timezone"));
-
- Set<String> set = (offsets.get(dist) != null) ?
- offsets.get(dist) : new HashSet<String>();
-
- set.add(location_name);
- offsets.put(dist, set);
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- return offsets;
- }
-
- private JSONObject availableLocations() {
- JSONObject locations = null;
- try {
- if(eipDefinition == null) updateEIPService();
- locations = eipDefinition.getJSONObject("locations");
- } catch (JSONException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
-
- return locations;
- }
-
- 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;
- }
-
- private String chooseHost(String location) {
- String chosen_host = "";
- try {
- JSONArray gateways = eipDefinition.getJSONArray("gateways");
- for (int i = 0; i < gateways.length(); i++) {
- JSONObject gw = gateways.getJSONObject(i);
- if ( gw.getString("location").equalsIgnoreCase(location) || location.isEmpty()){
- chosen_host = eipDefinition.getJSONObject("locations").getJSONObject(gw.getString("location")).getString("name");
- break;
- }
- }
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return chosen_host;
- }
-
- 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);
- }
-
- /**
- * 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(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");
- }
-
- tellToReceiver(ACTION_STOP_EIP, Activity.RESULT_OK);
- }
-
- private void tellToReceiver(String action, int resultCode) {
- if (mReceiver != null){
- Bundle resultData = new Bundle();
- resultData.putString(REQUEST_TAG, action);
- mReceiver.send(resultCode, resultData);
- }
- }
-
- /**
- * 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() {
- int resultCode = Activity.RESULT_CANCELED;
- boolean is_connected = isConnected();
-
- resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED;
-
- tellToReceiver(ACTION_IS_EIP_RUNNING, resultCode);
- }
-
- 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.
- * TODO Implement API call to refresh eip-service.json from the provider
- */
- private void updateEIPService() {
- try {
- String eip_definition_string = preferences.getString(KEY, "");
- if(eip_definition_string.isEmpty() == false) {
- eipDefinition = new JSONObject(eip_definition_string);
- }
- deleteAllVpnProfiles();
- updateGateways();
- if(mReceiver != null) mReceiver.send(Activity.RESULT_OK, Bundle.EMPTY);
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- private void deleteAllVpnProfiles() {
- ProfileManager vpl = ProfileManager.getInstance(context);
- Collection<VpnProfile> profiles = vpl.getProfiles();
- profiles.removeAll(profiles);
- }
-
- /**
- * Walk the list of gateways defined in eip-service.json and parse them into
- * OVPNGateway objects.
- * TODO Store the OVPNGateways (as Serializable) in SharedPreferences
- */
- private void updateGateways(){
- JSONArray gatewaysDefined = null;
- try {
- if(eipDefinition == null) updateEIPService();
- gatewaysDefined = eipDefinition.getJSONArray("gateways");
- for ( int i=0 ; i < gatewaysDefined.length(); i++ ){
- JSONObject gw = null;
- gw = gatewaysDefined.getJSONObject(i);
-
- if ( gw.getJSONObject("capabilities").getJSONArray("transport").toString().contains("openvpn") )
- new OVPNGateway(gw);
- }
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- preferences.edit().putInt(PARSED_SERIAL, eipDefinition.optInt(Provider.API_RETURN_SERIAL)).commit();
- }
-
- private void checkCertValidity() {
- String certificate = preferences.getString(CERTIFICATE, "");
- checkCertValidity(certificate);
- }
-
- private void checkCertValidity(String certificate_string) {
- if(!certificate_string.isEmpty()) {
- X509Certificate certificate = ConfigHelper.parseX509CertificateFromString(certificate_string);
-
- Calendar offset_date = calculateOffsetCertificateValidity(certificate);
- Bundle result = new Bundle();
- result.putString(REQUEST_TAG, ACTION_CHECK_CERT_VALIDITY);
- try {
- Log.d(TAG, "offset_date = " + offset_date.getTime().toString());
- certificate.checkValidity(offset_date.getTime());
- mReceiver.send(Activity.RESULT_OK, result);
- Log.d(TAG, "Valid certificate");
- } catch(CertificateExpiredException e) {
- mReceiver.send(Activity.RESULT_CANCELED, result);
- Log.d(TAG, "Updating certificate");
- } catch(CertificateNotYetValidException e) {
- mReceiver.send(Activity.RESULT_CANCELED, result);
- }
- }
- }
-
- private Calendar calculateOffsetCertificateValidity(X509Certificate certificate) {
- String current_date = certificate_date_format.format(Calendar.getInstance().getTime()).toString();
-
- String date_string = preferences.getString(DATE_FROM_CERTIFICATE, current_date);
-
- Calendar offset_date = Calendar.getInstance();
- try {
- Date date = certificate_date_format.parse(date_string);
- long difference = Math.abs(date.getTime() - certificate.getNotAfter().getTime())/2;
- long current_date_millis = offset_date.getTimeInMillis();
- offset_date.setTimeInMillis(current_date_millis + difference);
- Log.d(TAG, "certificate not after = " + certificate.getNotAfter());
- } catch(ParseException e) {
- e.printStackTrace();
- }
-
- return offset_date;
- }
-
- /**
- * OVPNGateway provides objects defining gateways and their options and metadata.
- * Each instance contains a VpnProfile for OpenVPN specific data and member
- * variables describing capabilities and location
- *
- * @author Sean Leonard <meanderingcode@aetherislands.net>
- */
- private class OVPNGateway {
-
- private String TAG = "OVPNGateway";
-
- private String mName;
- private VpnProfile mVpnProfile;
- private JSONObject mGateway;
- private HashMap<String,Vector<Vector<String>>> options = new HashMap<String, Vector<Vector<String>>>();
-
-
- /**
- * Attempts to retrieve a VpnProfile by name and build an OVPNGateway around it.
- * FIXME This needs to become a findGatewayByName() method
- *
- * @param name The hostname of the gateway to inflate
- */
- private OVPNGateway(String name){
- mName = name;
-
- this.loadVpnProfile();
- }
-
- private void loadVpnProfile() {
- ProfileManager vpl = ProfileManager.getInstance(context);
- try {
- if ( mName == null )
- mVpnProfile = vpl.getProfiles().iterator().next();
- else
- mVpnProfile = vpl.getProfileByName(mName);
- } catch (NoSuchElementException e) {
- updateEIPService();
- this.loadVpnProfile(); // FIXME catch infinite loops
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- /**
- * Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json
- * and create a VpnProfile belonging to it.
- *
- * @param gateway The JSON OpenVPN gateway definition to parse
- */
- protected OVPNGateway(JSONObject gateway){
-
- mGateway = gateway;
-
- // Currently deletes VpnProfile for host, if there already is one, and builds new
- ProfileManager vpl = ProfileManager.getInstance(context);
- Collection<VpnProfile> profiles = vpl.getProfiles();
- for (Iterator<VpnProfile> it = profiles.iterator(); it.hasNext(); ){
- VpnProfile p = it.next();
-
- if ( p.mName.equalsIgnoreCase( mName ) ) {
- it.remove();
- vpl.removeProfile(context, p);
- }
- }
-
- this.createVPNProfile();
-
- vpl.addProfile(mVpnProfile);
- vpl.saveProfile(context, mVpnProfile);
- vpl.saveProfileList(context);
- }
-
- /**
- * Create and attach the VpnProfile to our gateway object
- */
- protected void createVPNProfile(){
- try {
- ConfigParser cp = new ConfigParser();
-
- JSONObject openvpn_configuration = eipDefinition.getJSONObject("openvpn_configuration");
- VpnConfigGenerator vpn_configuration_generator = new VpnConfigGenerator(preferences, openvpn_configuration, mGateway);
- String configuration = vpn_configuration_generator.generate();
-
- cp.parseConfig(new StringReader(configuration));
- mVpnProfile = cp.convertProfile();
- mVpnProfile.mName = mName = locationAsName();
- Log.v(TAG,"Created VPNProfile");
-
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } 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 6d223dd6..592a9552 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
@@ -1,14 +1,5 @@
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;
-import de.blinkt.openvpn.core.VpnStatus.StateListener;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
@@ -19,99 +10,110 @@ import android.os.Handler;
import android.os.ResultReceiver;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewGroup;
-import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.CompoundButton;
-import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
import android.widget.Switch;
import android.widget.TextView;
-public class EipServiceFragment extends Fragment implements StateListener, OnCheckedChangeListener {
+import java.util.Observable;
+import java.util.Observer;
+
+import de.blinkt.openvpn.activities.DisconnectVPN;
+import se.leap.bitmaskclient.eip.Constants;
+import se.leap.bitmaskclient.eip.EIP;
+import se.leap.bitmaskclient.eip.EipStatus;
+
+public class EipServiceFragment extends Fragment implements Observer, CompoundButton.OnCheckedChangeListener {
- protected static final String IS_EIP_PENDING = "is_eip_pending";
+ public static String TAG = "se.leap.bitmask.EipServiceFragment";
+
+ protected static final String IS_PENDING = TAG + ".is_pending";
+ protected static final String IS_CONNECTED = TAG + ".is_connected";
+ protected static final String STATUS_MESSAGE = TAG + ".status_message";
public static final String START_ON_BOOT = "start on boot";
-
- private View eipFragment;
- private static Switch eipSwitch;
- private View eipDetail;
- private TextView eipStatus;
+ private View eipFragment;
+ private static Switch eipSwitch;
+ private TextView status_message;
+
+ private static Activity parent_activity;
private static EIPReceiver mEIPReceiver;
+ private static EipStatus eip_status;
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ parent_activity = activity;
+ }
- public static String TAG = "se.leap.bitmask.EipServiceFragment";
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ 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) {
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false);
- eipDetail = ((RelativeLayout) eipFragment.findViewById(R.id.eipDetail));
- eipDetail.setVisibility(View.VISIBLE);
+ eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false);
+ View eipDetail = eipFragment.findViewById(R.id.eipDetail);
+ eipDetail.setVisibility(View.VISIBLE);
- View eipSettings = eipFragment.findViewById(R.id.eipSettings);
- eipSettings.setVisibility(View.GONE); // FIXME too!
+ View eipSettings = eipFragment.findViewById(R.id.eipSettings);
+ eipSettings.setVisibility(View.GONE); // FIXME too!
- 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.setOnCheckedChangeListener(this);
-
- if(getArguments() != null && getArguments().containsKey(START_ON_BOOT) && getArguments().getBoolean(START_ON_BOOT))
- startEipFromScratch();
+ if (eip_status.isConnecting())
+ eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE);
- return eipFragment;
- }
+ status_message = (TextView) eipFragment.findViewById(R.id.status_message);
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ eipSwitch = (Switch) eipFragment.findViewById(R.id.eipSwitch);
+ Log.d(TAG, "onCreateView, eipSwitch is checked? " + eipSwitch.isChecked());
+ eipSwitch.setOnCheckedChangeListener(this);
- mEIPReceiver = new EIPReceiver(new Handler());
-
- if (savedInstanceState != null)
- EIP.mIsStarting = savedInstanceState.getBoolean(IS_EIP_PENDING);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- VpnStatus.addStateListener(this);
+ if(getArguments() != null && getArguments().containsKey(START_ON_BOOT) && getArguments().getBoolean(START_ON_BOOT))
+ startEipFromScratch();
- eipCommand(EIP.ACTION_CHECK_CERT_VALIDITY);
- }
-
- @Override
- public void onPause() {
- super.onPause();
+ if (savedInstanceState != null) {
+ setStatusMessage(savedInstanceState.getString(STATUS_MESSAGE));
+ if(savedInstanceState.getBoolean(IS_PENDING))
+ eip_status.setConnecting();
+ else if(savedInstanceState.getBoolean(IS_CONNECTED)) {
+ eip_status.setConnectedOrDisconnected();
+ }
+ }
+ return eipFragment;
+ }
- VpnStatus.removeStateListener(this);
- }
+ @Override
+ public void onResume() {
+ super.onResume();
+ eipCommand(Constants.ACTION_CHECK_CERT_VALIDITY);
+ }
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putBoolean(IS_EIP_PENDING, EIP.mIsStarting);
- }
+ @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);
+ }
protected void saveEipStatus() {
boolean eip_is_on = false;
- Log.d("bitmask", "saveEipStatus");
+ Log.d(TAG, "saveEipStatus");
if(eipSwitch.isChecked()) {
eip_is_on = true;
}
- if(getActivity() != null)
+ if(parent_activity != null)
Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, eip_is_on).commit();
}
+
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.equals(eipSwitch)){
@@ -133,48 +135,46 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
startEipFromScratch();
else if(canLogInToStartEIP()) {
Log.d(TAG, "Can Log In to start EIP");
- Dashboard dashboard = (Dashboard) getActivity();
+ Dashboard dashboard = (Dashboard) parent_activity;
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();
+ boolean certificateExists = !Dashboard.preferences.getString(Constants.CERTIFICATE, "").isEmpty();
+ boolean isAllowedAnon = Dashboard.preferences.getBoolean(Constants.ALLOWED_ANON, false);
+ return (isAllowedAnon || certificateExists) && !eip_status.isConnected();
}
private boolean canLogInToStartEIP() {
- boolean isAllowedRegistered = Dashboard.preferences.getBoolean(EIP.ALLOWED_REGISTERED, false);
+ 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.mIsStarting && !EIP.isConnected();
+ return isAllowedRegistered && !isLoggedIn && !eip_status.isConnecting() && !eip_status.isConnected();
}
private void handleSwitchOff() {
- if(EIP.mIsStarting) {
+ if(eip_status.isConnecting()) {
askPendingStartCancellation();
- } else if(EIP.isConnected()) {
- Log.d(TAG, "Stopping EIP");
+ } else if(eip_status.isConnected()) {
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))
+ AlertDialog.Builder alertBuilder = new AlertDialog.Builder(parent_activity);
+ alertBuilder.setTitle(parent_activity.getString(R.string.eip_cancel_connect_title))
+ .setMessage(parent_activity.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() {
+ .setNegativeButton(parent_activity.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);
}
})
@@ -182,243 +182,185 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
}
public void startEipFromScratch() {
- EIP.mIsStarting = true;
eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE);
- String status = getResources().getString(R.string.eip_status_start_pending);
- setEipStatus(status);
+ String status = parent_activity.getString(R.string.eip_status_start_pending);
+ setStatusMessage(status);
if(!eipSwitch.isChecked()) {
- Log.d(TAG, "startEipFromScratch checks the switch to true");
eipSwitch.setChecked(true);
saveEipStatus();
}
- eipCommand(EIP.ACTION_START_EIP);
+ eipCommand(Constants.ACTION_START_EIP);
}
protected void stopEIP() {
- EIP.mIsStarting = false;
- View eipProgressBar = getActivity().findViewById(R.id.eipProgress);
+ View eipProgressBar = parent_activity.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);
+ String status = parent_activity.getString(R.string.eip_state_not_connected);
+ setStatusMessage(status);
+ eipCommand(Constants.ACTION_STOP_EIP);
}
- /**
- * Send a command to EIP
- *
- * @param action A valid String constant from EIP class representing an Intent
- * filter for the EIP class
- */
- private void eipCommand(String action){
- // TODO validate "action"...how do we get the list of intent-filters for a class via Android API?
- Intent vpn_intent = new Intent(getActivity().getApplicationContext(), EIP.class);
- vpn_intent.setAction(action);
- vpn_intent.putExtra(EIP.RECEIVER_TAG, mEIPReceiver);
- getActivity().startService(vpn_intent);
- }
+ /**
+ * Send a command to EIP
+ *
+ * @param action A valid String constant from EIP class representing an Intent
+ * filter for the EIP class
+ */
+ private void eipCommand(String action){
+ // TODO validate "action"...how do we get the list of intent-filters for a class via Android API?
+ Intent vpn_intent = new Intent(parent_activity.getApplicationContext(), EIP.class);
+ vpn_intent.setAction(action);
+ vpn_intent.putExtra(Constants.RECEIVER_TAG, mEIPReceiver);
+ parent_activity.startService(vpn_intent);
+ }
@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);
+ public void update (Observable observable, Object data) {
+ if(observable instanceof EipStatus) {
+ eip_status = (EipStatus) observable;
+ final EipStatus eip_status = (EipStatus) observable;
+ parent_activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ handleNewState(eip_status);
}
});
- } else if(justDecidedOnDisconnect && level == ConnectionStatus.LEVEL_CONNECTED) {
- EIP.lastConnectionStatusLevel = ConnectionStatus.LEVEL_NOTCONNECTED;
- updateState(state, logmessage, localizedResId, level);
- } // else if(isNewLevel || level == ConnectionStatus.LEVEL_AUTH_FAILED)
- // handleNewState(state, logmessage, localizedResId, level);
+ }
}
- private void handleNewState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) {
- if (level == ConnectionStatus.LEVEL_CONNECTED)
+ private void handleNewState(EipStatus eip_status) {
+ Log.d(TAG, "handleNewState: " + eip_status.toString());
+ if(eip_status.wantsToDisconnect())
+ setDisconnectedUI();
+ else if (eip_status.isConnected())
setConnectedUI();
- else if (isDisconnectedLevel(level) && !EIP.mIsStarting)
+ else if (eip_status.isDisconnected() && !eip_status.isConnecting())
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);
- // else if (level == ConnectionStatus.LEVEL_AUTH_FAILED)
- // handleSwitchOn();
- }
-
- private boolean isDisconnectedLevel(final ConnectionStatus level) {
- return level == ConnectionStatus.LEVEL_NOTCONNECTED || level == ConnectionStatus.LEVEL_AUTH_FAILED;
+ else
+ setInProgressUI(eip_status);
}
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);
+ Log.d(TAG, "setConnectedUi? " + eip_status.isConnected());
adjustSwitch();
+ setStatusMessage(parent_activity.getString(R.string.eip_state_connected));
}
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();
+ setStatusMessage(parent_activity.getString(R.string.eip_state_not_connected));
}
- private void adjustSwitch() {
- if(EIP.isConnected()) {
+ private void adjustSwitch() {
+ if(eip_status.isConnected() || eip_status.isConnecting()) {
+ Log.d(TAG, "adjustSwitch, isConnected || isConnecting, is checked? " + eipSwitch.isChecked());
if(!eipSwitch.isChecked()) {
eipSwitch.setChecked(true);
}
} else {
+ Log.d(TAG, "adjustSwitch, !isConnected && !isConnecting? " + eip_status.toString());
+
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);
- }
+ private void setInProgressUI(EipStatus eip_status) {
+ int localizedResId = eip_status.getLocalizedResId();
+ String logmessage = eip_status.getLogMessage();
+ String prefix = parent_activity.getString(localizedResId);
+
+ setStatusMessage(prefix + " " + logmessage);
+ adjustSwitch();
}
- protected void setEipStatus(String status) {
- if(eipStatus == null)
- eipStatus = (TextView) getActivity().findViewById(R.id.eipStatus);
- eipStatus.setText(status);
+ protected void setStatusMessage(String status) {
+ if(status_message == null)
+ status_message = (TextView) parent_activity.findViewById(R.id.status_message);
+ status_message.setText(status);
}
private void hideProgressBar() {
- if(getActivity() != null && getActivity().findViewById(R.id.eipProgress) != null)
- getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE);
+ if(parent_activity != null && parent_activity.findViewById(R.id.eipProgress) != null)
+ parent_activity.findViewById(R.id.eipProgress).setVisibility(View.GONE);
}
- /**
- * Inner class for handling messages related to EIP status and control requests
- *
- * @author Sean Leonard <meanderingcode@aetherislands.net>
- */
- protected class EIPReceiver extends ResultReceiver {
+ protected class EIPReceiver extends ResultReceiver {
- protected EIPReceiver(Handler handler){
- super(handler);
- }
+ protected EIPReceiver(Handler handler){
+ super(handler);
+ }
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- super.onReceiveResult(resultCode, resultData);
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ super.onReceiveResult(resultCode, resultData);
- String request = resultData.getString(EIP.REQUEST_TAG);
- boolean checked = false;
-
- if (request == EIP.ACTION_IS_EIP_RUNNING) {
- switch (resultCode){
- case Activity.RESULT_OK:
- checked = true;
- break;
- case Activity.RESULT_CANCELED:
- checked = false;
- break;
- }
- } else if (request == EIP.ACTION_START_EIP) {
- switch (resultCode){
- case Activity.RESULT_OK:
- 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;
- eipFragment.findViewById(R.id.eipProgress).setVisibility(View.GONE);
- break;
- }
- } else if (request == EIP.ACTION_STOP_EIP) {
- switch (resultCode){
- case Activity.RESULT_OK:
- checked = false;
- break;
- case Activity.RESULT_CANCELED:
- checked = true;
- break;
- }
- } else if (request == EIP.EIP_NOTIFICATION) {
- switch (resultCode){
- case Activity.RESULT_OK:
- checked = true;
- break;
- case Activity.RESULT_CANCELED:
- checked = false;
- break;
- }
- } 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.showProgressBar();
- String status = getResources().getString(R.string.updating_certificate_message);
- setEipStatus(status);
-
- if(LeapSRPSession.getToken().isEmpty() && !Dashboard.preferences.getBoolean(EIP.ALLOWED_ANON, false)) {
- dashboard.logInDialog(Bundle.EMPTY);
- } else {
-
- 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;
- }
+ String request = resultData.getString(Constants.REQUEST_TAG);
+
+ if (request.equals(Constants.ACTION_START_EIP)) {
+ switch (resultCode){
+ case Activity.RESULT_OK:
+ Log.d(TAG, "Action start eip = Result OK");
+ eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE);
+ break;
+ case Activity.RESULT_CANCELED:
+ eipFragment.findViewById(R.id.eipProgress).setVisibility(View.GONE);
+ break;
+ }
+ } else if (request.equals(Constants.ACTION_STOP_EIP)) {
+ switch (resultCode){
+ case Activity.RESULT_OK:
+ Intent disconnect_vpn = new Intent(parent_activity, DisconnectVPN.class);
+ parent_activity.startActivityForResult(disconnect_vpn, EIP.DISCONNECT);
+ eip_status.setDisconnecting();
+ 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:
+ Dashboard dashboard = (Dashboard) parent_activity;
+
+ dashboard.showProgressBar();
+ String status = parent_activity.getString(R.string.updating_certificate_message);
+ setStatusMessage(status);
+ if(LeapSRPSession.getToken().isEmpty() && !Dashboard.preferences.getBoolean(Constants.ALLOWED_ANON, false)) {
+ dashboard.logInDialog(Bundle.EMPTY);
+ } else {
+ Intent provider_API_command = new Intent(parent_activity, 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);
+ parent_activity.startService(provider_API_command);
+ }
+ break;
}
+ }
}
+ }
public static EIPReceiver getReceiver() {
return mEIPReceiver;
}
-
- public static boolean isEipSwitchChecked() {
- return eipSwitch.isChecked();
- }
-
- public void checkEipSwitch(boolean checked) {
- eipSwitch.setChecked(checked);
- // Log.d(TAG, "checkEipSwitch");
- // onCheckedChanged(eipSwitch, checked);
- }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
index a953a710..989dc395 100644
--- a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
+++ b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
@@ -17,13 +17,14 @@
package se.leap.bitmaskclient;
+import org.jboss.security.srp.SRPParameters;
+
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
-import org.jboss.security.srp.SRPParameters;
/**
* Implements all SRP algorithm logic.
diff --git a/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java b/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java
index 5a0c9a6d..5263392e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java
@@ -16,19 +16,13 @@
*/
package se.leap.bitmaskclient;
-import se.leap.bitmaskclient.R;
-import android.R.color;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
-import android.content.res.ColorStateList;
import android.os.Bundle;
-import android.provider.CalendarContract.Colors;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.BounceInterpolator;
import android.widget.EditText;
import android.widget.TextView;
@@ -47,6 +41,8 @@ public class LogInDialog extends SessionDialogInterface {
final public static String TAG = LogInDialog.class.getSimpleName();
+ private static LogInDialog dialog;
+
private static boolean is_eip_pending = false;
public AlertDialog onCreateDialog(Bundle savedInstanceState) {
@@ -55,32 +51,28 @@ public class LogInDialog extends SessionDialogInterface {
View log_in_dialog_view = inflater.inflate(R.layout.log_in_dialog, null);
final TextView user_message = (TextView)log_in_dialog_view.findViewById(R.id.user_message);
- if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) {
- user_message.setText(getArguments().getString(getResources().getString(R.string.user_message)));
- } else {
- user_message.setVisibility(View.GONE);
- }
-
final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered);
- if(getArguments() != null && getArguments().containsKey(USERNAME)) {
- String username = getArguments().getString(USERNAME);
- username_field.setText(username);
- }
- if (getArguments() != null && getArguments().containsKey(USERNAME_MISSING)) {
- username_field.setError(getResources().getString(R.string.username_ask));
- }
-
final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered);
+
if(!username_field.getText().toString().isEmpty() && password_field.isFocusable()) {
password_field.requestFocus();
}
- if (getArguments() != null && getArguments().containsKey(PASSWORD_INVALID_LENGTH)) {
- password_field.setError(getResources().getString(R.string.error_not_valid_password_user_message));
- }
- if(getArguments() != null && getArguments().getBoolean(EipServiceFragment.IS_EIP_PENDING, false)) {
- is_eip_pending = true;
+ if (getArguments() != null) {
+ is_eip_pending = getArguments().getBoolean(EipServiceFragment.IS_PENDING, false);
+ if (getArguments().containsKey(PASSWORD_INVALID_LENGTH))
+ password_field.setError(getResources().getString(R.string.error_not_valid_password_user_message));
+ if (getArguments().containsKey(USERNAME)) {
+ String username = getArguments().getString(USERNAME);
+ username_field.setText(username);
}
-
+ if (getArguments().containsKey(USERNAME_MISSING)) {
+ username_field.setError(getResources().getString(R.string.username_ask));
+ }
+ if(getArguments().containsKey(getResources().getString(R.string.user_message)))
+ user_message.setText(getArguments().getString(getResources().getString(R.string.user_message)));
+ else
+ user_message.setVisibility(View.GONE);
+ }
builder.setView(log_in_dialog_view)
.setPositiveButton(R.string.login_button, new DialogInterface.OnClickListener() {
@@ -116,7 +108,6 @@ public class LogInDialog extends SessionDialogInterface {
*/
public interface LogInDialogInterface {
public void logIn(String username, String password);
- public void cancelAuthedEipOn();
public void signUp(String username, String password);
public void cancelLoginOrSignup();
}
@@ -127,8 +118,10 @@ public class LogInDialog extends SessionDialogInterface {
* @return a new instance of this DialogFragment.
*/
public static DialogFragment newInstance() {
- LogInDialog dialog_fragment = new LogInDialog();
- return dialog_fragment;
+ if(dialog == null)
+ dialog = new LogInDialog();
+
+ return dialog;
}
@Override
@@ -146,6 +139,6 @@ public class LogInDialog extends SessionDialogInterface {
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
if(is_eip_pending)
- interface_with_Dashboard.cancelAuthedEipOn();
+ interface_with_Dashboard.cancelLoginOrSignup();
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java b/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
index eb196d46..07ed6c8f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
@@ -3,8 +3,8 @@ package se.leap.bitmaskclient;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.util.Log;
+import se.leap.bitmaskclient.eip.Constants;
public class OnBootReceiver extends BroadcastReceiver {
@@ -14,7 +14,7 @@ public class OnBootReceiver extends BroadcastReceiver {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
if (!context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Context.MODE_PRIVATE).getString(Provider.KEY, "").isEmpty() && context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Context.MODE_PRIVATE).getBoolean(Dashboard.START_ON_BOOT, false)) {
Intent dashboard_intent = new Intent(context, Dashboard.class);
- dashboard_intent.setAction(EIP.ACTION_START_EIP);
+ 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/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java
index 8d6385e0..fa1a4fb5 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Provider.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java
@@ -16,17 +16,17 @@
*/
package se.leap.bitmaskclient;
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.Locale;
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
-import android.content.Context;
-import android.app.Activity;
-import android.content.SharedPreferences;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Locale;
/**
* @author Sean Leonard <meanderingcode@aetherislands.net>
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java
index 43bba085..1148e65e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListAdapter.java
@@ -1,7 +1,5 @@
package se.leap.bitmaskclient;
-import java.util.List;
-
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
@@ -9,6 +7,8 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TwoLineListItem;
+import java.util.List;
+
public class ProviderListAdapter<T> extends ArrayAdapter<T> {
private static boolean[] hidden = null;
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListFragment.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListFragment.java
index db414d87..e5baebc0 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderListFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListFragment.java
@@ -16,8 +16,6 @@
*/
package se.leap.bitmaskclient;
-import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
import android.app.Activity;
import android.app.ListFragment;
import android.os.Bundle;
@@ -26,11 +24,12 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
+import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
+
/**
* A list fragment representing a list of Providers. This fragment
* also supports tablet devices by allowing list items to be given an
- * 'activated' state upon selection. This helps indicate which item is
- * currently being viewed in a {@link DashboardFragment}.
+ * 'activated' state upon selection.
* <p>
* Activities containing this fragment MUST implement the {@link Callbacks}
* interface.
@@ -123,7 +122,7 @@ public class ProviderListFragment extends ListFragment {
if(getArguments() != null && getArguments().containsKey(TOP_PADDING)) {
int topPadding = getArguments().getInt(TOP_PADDING);
View current_view = getView();
- getView().setPadding(current_view.getPaddingLeft(), topPadding, current_view.getPaddingRight(), current_view.getPaddingBottom());
+ current_view.setPadding(current_view.getPaddingLeft(), topPadding, current_view.getPaddingRight(), current_view.getPaddingBottom());
}
}
@@ -215,7 +214,7 @@ public class ProviderListFragment extends ListFragment {
real_count--;
} else {
i++;
- }
+ }
}
public void unhideAll() {
diff --git a/app/src/main/java/se/leap/bitmaskclient/SessionDialogInterface.java b/app/src/main/java/se/leap/bitmaskclient/SessionDialogInterface.java
index 7b08a4d1..66b86ccd 100644
--- a/app/src/main/java/se/leap/bitmaskclient/SessionDialogInterface.java
+++ b/app/src/main/java/se/leap/bitmaskclient/SessionDialogInterface.java
@@ -17,10 +17,8 @@
package se.leap.bitmaskclient;
import android.app.Activity;
-import android.app.AlertDialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
-import android.os.Bundle;
/**
* @author parmegv
diff --git a/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java b/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java
index 3cb41f4f..f6d6cc3f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java
@@ -16,19 +16,13 @@
*/
package se.leap.bitmaskclient;
-import se.leap.bitmaskclient.R;
-import android.R.color;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
-import android.content.res.ColorStateList;
import android.os.Bundle;
-import android.provider.CalendarContract.Colors;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.BounceInterpolator;
import android.widget.EditText;
import android.widget.TextView;
@@ -46,6 +40,7 @@ public class SignUpDialog extends SessionDialogInterface {
final public static String TAG = SignUpDialog.class.getSimpleName();
+ private static SignUpDialog dialog;
private static boolean is_eip_pending = false;
public AlertDialog onCreateDialog(Bundle savedInstanceState) {
@@ -54,32 +49,27 @@ public class SignUpDialog extends SessionDialogInterface {
View log_in_dialog_view = inflater.inflate(R.layout.log_in_dialog, null);
final TextView user_message = (TextView)log_in_dialog_view.findViewById(R.id.user_message);
- if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) {
- user_message.setText(getArguments().getString(getResources().getString(R.string.user_message)));
- } else {
- user_message.setVisibility(View.GONE);
- }
-
final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered);
- if(getArguments() != null && getArguments().containsKey(USERNAME)) {
- String username = getArguments().getString(USERNAME);
- username_field.setText(username);
- }
- if (getArguments() != null && getArguments().containsKey(USERNAME_MISSING)) {
- username_field.setError(getResources().getString(R.string.username_ask));
- }
-
final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered);
+
if(!username_field.getText().toString().isEmpty() && password_field.isFocusable()) {
password_field.requestFocus();
}
- if (getArguments() != null && getArguments().containsKey(PASSWORD_INVALID_LENGTH)) {
- password_field.setError(getResources().getString(R.string.error_not_valid_password_user_message));
- }
- if(getArguments() != null && getArguments().getBoolean(EipServiceFragment.IS_EIP_PENDING, false)) {
- is_eip_pending = true;
+ if (getArguments() != null) {
+ is_eip_pending = getArguments().getBoolean(EipServiceFragment.IS_PENDING, false);
+ if (getArguments().containsKey(PASSWORD_INVALID_LENGTH))
+ password_field.setError(getResources().getString(R.string.error_not_valid_password_user_message));
+ if(getArguments().containsKey(USERNAME_MISSING))
+ username_field.setError(getResources().getString(R.string.username_ask));
+ if(getArguments().containsKey(USERNAME)) {
+ String username = getArguments().getString(USERNAME);
+ username_field.setText(username);
}
-
+ if(getArguments().containsKey(getResources().getString(R.string.user_message)))
+ user_message.setText(getArguments().getString(getResources().getString(R.string.user_message)));
+ else
+ user_message.setVisibility(View.GONE);
+ }
builder.setView(log_in_dialog_view)
.setPositiveButton(R.string.signup_button, new DialogInterface.OnClickListener() {
@@ -108,7 +98,6 @@ public class SignUpDialog extends SessionDialogInterface {
*/
public interface SignUpDialogInterface {
public void signUp(String username, String password);
- public void cancelAuthedEipOn();
public void cancelLoginOrSignup();
}
@@ -118,8 +107,9 @@ public class SignUpDialog extends SessionDialogInterface {
* @return a new instance of this DialogFragment.
*/
public static DialogFragment newInstance() {
- SignUpDialog dialog_fragment = new SignUpDialog();
- return dialog_fragment;
+ if(dialog == null)
+ dialog = new SignUpDialog();
+ return dialog;
}
@Override
@@ -136,7 +126,7 @@ public class SignUpDialog extends SessionDialogInterface {
@Override
public void onCancel(DialogInterface dialog) {
if(is_eip_pending)
- interface_with_Dashboard.cancelAuthedEipOn();
+ interface_with_Dashboard.cancelLoginOrSignup();
super.onCancel(dialog);
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java b/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java
new file mode 100644
index 00000000..e1a7e616
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Constants.java
@@ -0,0 +1,47 @@
+/**
+ * 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.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";
+ public final static String ACTION_UPDATE_EIP_SERVICE = TAG + ".UPDATE_EIP_SERVICE";
+ public final static String ACTION_IS_EIP_RUNNING = TAG + ".IS_RUNNING";
+ public final static String EIP_NOTIFICATION = TAG + ".EIP_NOTIFICATION";
+ 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 = TAG + ".PRIVATE_KEY";
+ public final static String KEY = TAG + ".KEY";
+ public final static String PARSED_SERIAL = TAG + ".PARSED_SERIAL";
+ public final static String RECEIVER_TAG = TAG + ".RECEIVER_TAG";
+ public final static String REQUEST_TAG = TAG + ".REQUEST_TAG";
+ public final static String START_BLOCKING_VPN_PROFILE = TAG + ".START_BLOCKING_VPN_PROFILE";
+
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
new file mode 100644
index 00000000..b4208556
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
@@ -0,0 +1,255 @@
+/**
+ * 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.eip;
+
+import android.app.Activity;
+import android.app.IntentService;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import de.blinkt.openvpn.LaunchVPN;
+import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.core.ProfileManager;
+import se.leap.bitmaskclient.Dashboard;
+import se.leap.bitmaskclient.EipServiceFragment;
+import se.leap.bitmaskclient.Provider;
+
+import static se.leap.bitmaskclient.eip.Constants.ACTION_CHECK_CERT_VALIDITY;
+import static se.leap.bitmaskclient.eip.Constants.ACTION_IS_EIP_RUNNING;
+import static se.leap.bitmaskclient.eip.Constants.ACTION_START_EIP;
+import static se.leap.bitmaskclient.eip.Constants.ACTION_STOP_EIP;
+import static se.leap.bitmaskclient.eip.Constants.ACTION_UPDATE_EIP_SERVICE;
+import static se.leap.bitmaskclient.eip.Constants.CERTIFICATE;
+import static se.leap.bitmaskclient.eip.Constants.KEY;
+import static se.leap.bitmaskclient.eip.Constants.PARSED_SERIAL;
+import static se.leap.bitmaskclient.eip.Constants.RECEIVER_TAG;
+import static se.leap.bitmaskclient.eip.Constants.REQUEST_TAG;
+
+/**
+ * EIP is the abstract base class for interacting with and managing the Encrypted
+ * Internet Proxy connection. Connections are started, stopped, and queried through
+ * this IntentService.
+ * Contains logic for parsing eip-service.json from the provider, configuring and selecting
+ * gateways, and controlling {@link de.blinkt.openvpn.core.OpenVPNService} connections.
+ *
+ * @author Sean Leonard <meanderingcode@aetherislands.net>
+ * @author Parménides GV <parmegv@sdf.org>
+ */
+public final class EIP extends IntentService {
+
+ public final static String TAG = EIP.class.getSimpleName();
+ 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 = null;
+ private static List<Gateway> gateways = new ArrayList<Gateway>();
+ private static ProfileManager profile_manager;
+ private static Gateway activeGateway = null;
+
+ public EIP(){
+ super("LEAPEIP");
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ context = getApplicationContext();
+ profile_manager = ProfileManager.getInstance(context);
+
+ preferences = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE);
+ refreshEipDefinition();
+ }
+
+ @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();
+ else if (action.equals(ACTION_UPDATE_EIP_SERVICE))
+ 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.isEmpty())
+ updateEIPService();
+ GatewaySelector gateway_selector = new GatewaySelector(gateways);
+ activeGateway = gateway_selector.select();
+ if(activeGateway != null && activeGateway.getProfile() != null) {
+ mReceiver = EipServiceFragment.getReceiver();
+ launchActiveGateway();
+ }
+ earlyRoutes();
+ }
+
+ /**
+ * Early routes are routes that block traffic until a new
+ * 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);
+ }
+
+ 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, activeGateway.getProfile().getName() );
+ intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true);
+ intent.putExtra(RECEIVER_TAG, mReceiver);
+ startActivity(intent);
+ }
+
+ /**
+ * 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() {
+ EipStatus eip_status = EipStatus.getInstance();
+ Log.d(TAG, "stopEip(): eip is connected? " + eip_status.isConnected());
+ int result_code = Activity.RESULT_CANCELED;
+ if(eip_status.isConnected())
+ result_code = Activity.RESULT_OK;
+
+ 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);
+ }
+
+ /**
+ * Loads eip-service.json from SharedPreferences, delete previous vpn profiles and add new gateways.
+ * TODO Implement API call to refresh eip-service.json from the provider
+ */
+ private void updateEIPService() {
+ refreshEipDefinition();
+ deleteAllVpnProfiles();
+ updateGateways();
+ tellToReceiver(ACTION_UPDATE_EIP_SERVICE, Activity.RESULT_OK);
+ }
+
+ private void refreshEipDefinition() {
+ try {
+ String eip_definition_string = preferences.getString(KEY, "");
+ if(!eip_definition_string.isEmpty()) {
+ eip_definition = new JSONObject(eip_definition_string);
+ }
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private void deleteAllVpnProfiles() {
+ Collection<VpnProfile> profiles = profile_manager.getProfiles();
+ profiles.removeAll(profiles);
+ }
+
+ /**
+ * Walk the list of gateways defined in eip-service.json and parse them into
+ * Gateway objects.
+ * TODO Store the Gateways (as Serializable) in SharedPreferences
+ */
+ private void updateGateways(){
+ try {
+ JSONArray gatewaysDefined = eip_definition.getJSONArray("gateways");
+ for ( int i=0 ; i < gatewaysDefined.length(); i++ ){
+ JSONObject gw = gatewaysDefined.getJSONObject(i);
+ if(isOpenVpnGateway(gw)) {
+ addGateway(new Gateway(eip_definition, context, gw));
+ }
+ }
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ preferences.edit().putInt(PARSED_SERIAL, eip_definition.optInt(Provider.API_RETURN_SERIAL)).apply();
+ }
+
+ private boolean isOpenVpnGateway(JSONObject gateway) {
+ try {
+ String transport = gateway.getJSONObject("capabilities").getJSONArray("transport").toString();
+ return transport.contains("openvpn");
+ } catch (JSONException e) {
+ return false;
+ }
+ }
+
+ private void addGateway(Gateway gateway) {
+ profile_manager.addProfile(gateway.getProfile());
+ gateways.add(gateway);
+ }
+
+ private void checkCertValidity() {
+ VpnCertificateValidator validator = new VpnCertificateValidator();
+ int resultCode = validator.isValid(preferences.getString(CERTIFICATE, "")) ?
+ Activity.RESULT_OK :
+ Activity.RESULT_CANCELED;
+ tellToReceiver(ACTION_CHECK_CERT_VALIDITY, resultCode);
+ }
+
+ private void tellToReceiver(String action, int resultCode) {
+ 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
new file mode 100644
index 00000000..4ac3bd6a
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
@@ -0,0 +1,138 @@
+/**
+ * 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.eip;
+
+import android.util.Log;
+
+import java.util.Observable;
+
+import de.blinkt.openvpn.core.VpnStatus;
+
+public class EipStatus extends Observable implements VpnStatus.StateListener {
+ public static String TAG = EipStatus.class.getSimpleName();
+ private static EipStatus current_status;
+
+ private static VpnStatus.ConnectionStatus level = VpnStatus.ConnectionStatus.LEVEL_NOTCONNECTED;
+ private static boolean wants_to_disconnect = false;
+
+ private String state, log_message;
+ private int localized_res_id;
+
+ public static EipStatus getInstance() {
+ if(current_status == null) {
+ current_status = new EipStatus();
+ VpnStatus.addStateListener(current_status);
+ }
+ return current_status;
+ }
+
+ 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();
+ }
+
+ public boolean wantsToDisconnect() {
+ return wants_to_disconnect;
+ }
+
+ public boolean isConnecting() {
+ return
+ !isConnected() &&
+ !isDisconnected() &&
+ !isPaused();
+ }
+
+ public boolean isConnected() {
+ return level == VpnStatus.ConnectionStatus.LEVEL_CONNECTED;
+ }
+
+ public boolean isDisconnected() {
+ return level == VpnStatus.ConnectionStatus.LEVEL_NOTCONNECTED;
+ }
+
+ public boolean isPaused() {
+ return level == VpnStatus.ConnectionStatus.LEVEL_VPNPAUSED;
+ }
+
+ public void setConnecting() {
+ 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();
+ }
+
+ public void setDisconnecting() {
+ wants_to_disconnect = false;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public String getLogMessage() {
+ return log_message;
+ }
+
+ public int getLocalizedResId() {
+ return localized_res_id;
+ }
+
+ public VpnStatus.ConnectionStatus getLevel() {
+ return level;
+ }
+
+ private void setState(String state) {
+ this.state = state;
+ }
+
+ private void setLogMessage(String log_message) {
+ this.log_message = log_message;
+ }
+
+ private void setLocalizedResId(int localized_res_id) {
+ this.localized_res_id = localized_res_id;
+ }
+
+ private void setLevel(VpnStatus.ConnectionStatus level) {
+ EipStatus.level = level;
+ }
+
+ @Override
+ public String 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
new file mode 100644
index 00000000..3ee9443c
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
@@ -0,0 +1,156 @@
+/**
+ * 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.eip;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Collection;
+import java.util.Iterator;
+
+import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.core.ConfigParser;
+import de.blinkt.openvpn.core.ProfileManager;
+import se.leap.bitmaskclient.Dashboard;
+
+/**
+ * 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 {
+
+ private String TAG = Gateway.class.getSimpleName();
+
+ private String mName;
+ private int timezone;
+ private JSONObject general_configuration;
+ private Context context;
+ private VpnProfile mVpnProfile;
+ private JSONObject mGateway;
+
+ /**
+ * Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json
+ * and create a VpnProfile belonging to it.
+ *
+ * @param gateway The JSON OpenVPN gateway definition to parse
+ */
+ protected Gateway(JSONObject eip_definition, Context context, JSONObject gateway){
+
+ mGateway = gateway;
+
+ this.context = context;
+ general_configuration = getGeneralConfiguration(eip_definition);
+ timezone = getTimezone(eip_definition);
+ mName = locationAsName(eip_definition);
+
+ // Currently deletes VpnProfile for host, if there already is one, and builds new
+ ProfileManager vpl = ProfileManager.getInstance(context);
+ Collection<VpnProfile> profiles = vpl.getProfiles();
+ for (Iterator<VpnProfile> it = profiles.iterator(); it.hasNext(); ){
+ VpnProfile p = it.next();
+
+ if ( p.mName.equalsIgnoreCase( mName ) ) {
+ it.remove();
+ vpl.removeProfile(context, p);
+ }
+ }
+
+ mVpnProfile = createVPNProfile();
+ mVpnProfile.mName = mName;
+
+ vpl.addProfile(mVpnProfile);
+ vpl.saveProfile(context, mVpnProfile);
+ vpl.saveProfileList(context);
+ }
+
+ private JSONObject getGeneralConfiguration(JSONObject eip_definition) {
+ 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");
+ }
+
+ private String locationAsName(JSONObject eip_definition) {
+ JSONObject location = getLocationInfo(eip_definition);
+ return location.optString("name");
+ }
+
+ private JSONObject getLocationInfo(JSONObject eip_definition) {
+ try {
+ JSONObject locations = eip_definition.getJSONObject("locations");
+
+ return locations.getJSONObject(mGateway.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();
+
+ SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE);
+ VpnConfigGenerator vpn_configuration_generator = new VpnConfigGenerator(preferences, general_configuration, mGateway);
+ 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;
+ }
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public VpnProfile getProfile() {
+ return mVpnProfile;
+ }
+
+ public int getTimezone() {
+ return timezone;
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
new file mode 100644
index 00000000..39ae7ca6
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java
@@ -0,0 +1,46 @@
+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;
+
+public class GatewaySelector {
+ List<Gateway> gateways;
+
+ public GatewaySelector(List<Gateway> gateways) {
+ this.gateways = gateways;
+ }
+
+ public Gateway select() {
+ return closestGateway();
+ }
+
+ private Gateway closestGateway() {
+ 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;
+ }
+
+ 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;
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java
index 3b286fbf..d79d8003 100644
--- a/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnLauncher.java
@@ -1,4 +1,4 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.eip;
import android.app.Activity;
import android.content.Intent;
@@ -8,7 +8,7 @@ import android.os.Bundle;
public class VoidVpnLauncher extends Activity {
private static final int VPN_USER_PERMISSION = 71;
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -28,7 +28,7 @@ public class VoidVpnLauncher extends Activity {
if(requestCode == VPN_USER_PERMISSION) {
if(resultCode == RESULT_OK) {
Intent void_vpn_service = new Intent(getApplicationContext(), VoidVpnService.class);
- void_vpn_service.setAction(VoidVpnService.START_BLOCKING_VPN_PROFILE);
+ void_vpn_service.setAction(Constants.START_BLOCKING_VPN_PROFILE);
startService(void_vpn_service);
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
index 7b597554..a6f9fe76 100644
--- a/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
@@ -1,19 +1,16 @@
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.eip;
import android.content.Intent;
-import android.os.Process;
import android.net.VpnService;
-import android.util.Log;
public class VoidVpnService extends VpnService {
- static final String START_BLOCKING_VPN_PROFILE = "se.leap.bitmaskclient.START_BLOCKING_VPN_PROFILE";
static final String TAG = VoidVpnService.class.getSimpleName();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
- if (action == START_BLOCKING_VPN_PROFILE) {
+ if (action == Constants.START_BLOCKING_VPN_PROFILE) {
new Thread(new Runnable() {
public void run() {
Builder builder = new Builder();
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java
new file mode 100644
index 00000000..6487f6c1
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java
@@ -0,0 +1,60 @@
+/**
+ * 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.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 se.leap.bitmaskclient.ConfigHelper;
+
+public class VpnCertificateValidator {
+ public final static String TAG = VpnCertificateValidator.class.getSimpleName();
+
+ public boolean isValid(String certificate) {
+ 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;
+ }
+ }
+
+ 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;
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
index ef049a3c..0c8e9a04 100644
--- a/app/src/main/java/se/leap/bitmaskclient/VpnConfigGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
@@ -14,18 +14,18 @@
* 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.eip;
import android.content.SharedPreferences;
import android.util.Log;
-import java.util.Iterator;
-import java.util.Vector;
+
import org.json.JSONArray;
-import org.json.JSONObject;
import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
import se.leap.bitmaskclient.Provider;
-import se.leap.bitmaskclient.EIP;
public class VpnConfigGenerator {
@@ -39,7 +39,7 @@ public class VpnConfigGenerator {
public VpnConfigGenerator(SharedPreferences preferences, JSONObject general_configuration, JSONObject gateway) {
this.general_configuration = general_configuration;
this.gateway = gateway;
- this.preferences = preferences;
+ VpnConfigGenerator.preferences = preferences;
}
public String generate() {
@@ -57,7 +57,6 @@ public class VpnConfigGenerator {
String common_options = "";
try {
Iterator keys = general_configuration.keys();
- Vector<Vector<String>> value = new Vector<Vector<String>>();
while ( keys.hasNext() ){
String key = keys.next().toString();
@@ -121,14 +120,14 @@ public class VpnConfigGenerator {
String key =
"<key>"
+ new_line
- + preferences.getString(EIP.PRIVATE_KEY, "")
+ + preferences.getString(Constants.PRIVATE_KEY, "")
+ new_line
+ "</key>";
String openvpn_cert =
"<cert>"
+ new_line
- + preferences.getString(EIP.CERTIFICATE, "")
+ + preferences.getString(Constants.CERTIFICATE, "")
+ new_line
+ "</cert>";