summaryrefslogtreecommitdiff
path: root/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderCredentialsBaseActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderCredentialsBaseActivity.java')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderCredentialsBaseActivity.java479
1 files changed, 479 insertions, 0 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderCredentialsBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderCredentialsBaseActivity.java
new file mode 100644
index 00000000..91d0de56
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderCredentialsBaseActivity.java
@@ -0,0 +1,479 @@
+/**
+ * Copyright (c) 2018 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.providersetup.activities;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import com.google.android.material.textfield.TextInputEditText;
+import com.google.android.material.textfield.TextInputLayout;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import androidx.appcompat.widget.AppCompatButton;
+import androidx.appcompat.widget.AppCompatTextView;
+import android.text.Editable;
+import android.text.Html;
+import android.text.TextWatcher;
+import android.text.method.LinkMovementMethod;
+import android.text.util.Linkify;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.TextView;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import butterknife.InjectView;
+import butterknife.OnClick;
+import se.leap.bitmaskclient.base.models.Constants.CREDENTIAL_ERRORS;
+import se.leap.bitmaskclient.base.models.Provider;
+import se.leap.bitmaskclient.providersetup.ProviderAPI;
+import se.leap.bitmaskclient.providersetup.ProviderAPICommand;
+import se.leap.bitmaskclient.R;
+
+import static android.text.TextUtils.isEmpty;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_PROVIDER_API_EVENT;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE;
+import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.base.models.Constants.CREDENTIALS_PASSWORD;
+import static se.leap.bitmaskclient.base.models.Constants.CREDENTIALS_USERNAME;
+import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.LOG_IN;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.SIGN_UP;
+import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE;
+
+/**
+ * Base Activity for activities concerning a provider interaction
+ *
+ * Created by fupduck on 09.01.18.
+ */
+
+public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseActivity {
+
+ final protected static String TAG = ProviderCredentialsBaseActivity.class.getName();
+
+ final private static String ACTIVITY_STATE = "ACTIVITY STATE";
+
+ final private static String SHOWING_FORM = "SHOWING_FORM";
+ final private static String PERFORMING_ACTION = "PERFORMING_ACTION";
+ final private static String USERNAME_ERROR = "USERNAME_ERROR";
+ final private static String PASSWORD_ERROR = "PASSWORD_ERROR";
+ final private static String PASSWORD_VERIFICATION_ERROR = "PASSWORD_VERIFICATION_ERROR";
+
+ protected Intent mConfigState = new Intent(SHOWING_FORM);
+ protected ProviderAPIBroadcastReceiver providerAPIBroadcastReceiver;
+
+ @InjectView(R.id.provider_credentials_user_message)
+ AppCompatTextView userMessage;
+
+ @InjectView(R.id.provider_credentials_username)
+ TextInputEditText usernameField;
+
+ @InjectView(R.id.provider_credentials_password)
+ TextInputEditText passwordField;
+
+ @InjectView(R.id.provider_credentials_password_verification)
+ TextInputEditText passwordVerificationField;
+
+ @InjectView(R.id.provider_credentials_username_error)
+ TextInputLayout usernameError;
+
+ @InjectView(R.id.provider_credentials_password_error)
+ TextInputLayout passwordError;
+
+ @InjectView(R.id.provider_credentials_password_verification_error)
+ TextInputLayout passwordVerificationError;
+
+ @InjectView(R.id.button)
+ AppCompatButton button;
+
+ private boolean isUsernameError = false;
+ private boolean isPasswordError = false;
+ private boolean isVerificationError = false;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.a_provider_credentials);
+ providerAPIBroadcastReceiver = new ProviderAPIBroadcastReceiver();
+
+ IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_PROVIDER_API_EVENT);
+ updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT);
+ LocalBroadcastManager.getInstance(this).registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter);
+
+ setUpListeners();
+ restoreState(savedInstanceState);
+
+ String userMessageString = getIntent().getStringExtra(USER_MESSAGE);
+ if (userMessageString != null) {
+ userMessage.setText(userMessageString);
+ userMessage.setVisibility(VISIBLE);
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ String action = mConfigState.getAction();
+ if (action == null) {
+ return;
+ }
+
+ if(action.equalsIgnoreCase(PERFORMING_ACTION)) {
+ showProgressBar();
+ }
+ }
+
+ protected void restoreState(Bundle savedInstance) {
+ super.restoreState(savedInstance);
+ if (savedInstance == null) {
+ return;
+ }
+ if (savedInstance.getString(USER_MESSAGE) != null) {
+ userMessage.setText(savedInstance.getString(USER_MESSAGE));
+ userMessage.setVisibility(VISIBLE);
+ }
+ updateUsernameError(savedInstance.getString(USERNAME_ERROR));
+ updatePasswordError(savedInstance.getString(PASSWORD_ERROR));
+ updateVerificationError(savedInstance.getString(PASSWORD_VERIFICATION_ERROR));
+ if (savedInstance.getString(ACTIVITY_STATE) != null) {
+ mConfigState.setAction(savedInstance.getString(ACTIVITY_STATE));
+ }
+ }
+
+ private void updateUsernameError(String usernameErrorString) {
+ usernameError.setError(usernameErrorString);
+ isUsernameError = usernameErrorString != null;
+ updateButton();
+ }
+
+ private void updatePasswordError(String passwordErrorString) {
+ passwordError.setError(passwordErrorString);
+ isPasswordError = passwordErrorString != null;
+ updateButton();
+ }
+
+ private void updateVerificationError(String verificationErrorString) {
+ passwordVerificationError.setError(verificationErrorString);
+ isVerificationError = verificationErrorString != null;
+ updateButton();
+ }
+
+ private void updateButton() {
+ button.setEnabled(!isPasswordError &&
+ !isUsernameError &&
+ !isVerificationError &&
+ !isEmpty(passwordField.getText()) &&
+ !isEmpty(usernameField.getText()) &&
+ !(passwordVerificationField.getVisibility() == VISIBLE &&
+ getPasswordVerification().length() == 0));
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ outState.putString(ACTIVITY_STATE, mConfigState.getAction());
+ if (userMessage.getText() != null && userMessage.getVisibility() == VISIBLE) {
+ outState.putString(USER_MESSAGE, userMessage.getText().toString());
+ }
+ if (usernameError.getError() != null) {
+ outState.putString(USERNAME_ERROR, usernameError.getError().toString());
+ }
+ if (passwordError.getError() != null) {
+ outState.putString(PASSWORD_ERROR, passwordError.getError().toString());
+ }
+ if (passwordVerificationError.getError() != null) {
+ outState.putString(PASSWORD_VERIFICATION_ERROR, passwordVerificationError.getError().toString());
+ }
+
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (providerAPIBroadcastReceiver != null)
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(providerAPIBroadcastReceiver);
+ }
+
+ @OnClick(R.id.button)
+ void handleButton() {
+ mConfigState.setAction(PERFORMING_ACTION);
+ hideKeyboard();
+ showProgressBar();
+ }
+
+ protected void setButtonText(@StringRes int buttonText) {
+ button.setText(buttonText);
+ }
+
+ String getUsername() {
+ String username = usernameField.getText().toString();
+ String providerDomain = provider.getDomain();
+ if (username.endsWith(providerDomain)) {
+ try {
+ return username.split("@" + providerDomain)[0];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return "";
+ }
+ }
+ return username;
+ }
+
+ String getPassword() {
+ return passwordField.getText().toString();
+ }
+
+ String getPasswordVerification() {
+ return passwordVerificationField.getText().toString();
+ }
+
+ void login(String username, String password) {
+
+ Bundle parameters = bundleUsernameAndPassword(username, password);
+ ProviderAPICommand.execute(this, LOG_IN, parameters, provider);
+ }
+
+ public void signUp(String username, String password) {
+
+ Bundle parameters = bundleUsernameAndPassword(username, password);
+ ProviderAPICommand.execute(this, SIGN_UP, parameters, provider);
+ }
+
+ void downloadVpnCertificate(Provider handledProvider) {
+ provider = handledProvider;
+ ProviderAPICommand.execute(this, DOWNLOAD_VPN_CERTIFICATE, provider);
+ }
+
+ protected Bundle bundleUsernameAndPassword(String username, String password) {
+ Bundle parameters = new Bundle();
+ if (!username.isEmpty())
+ parameters.putString(CREDENTIALS_USERNAME, username);
+ if (!password.isEmpty())
+ parameters.putString(CREDENTIALS_PASSWORD, password);
+ return parameters;
+ }
+
+ private void setUpListeners() {
+ usernameField.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (getUsername().equalsIgnoreCase("")) {
+ s.clear();
+ updateUsernameError(getString(R.string.username_ask));
+ } else {
+ updateUsernameError(null);
+ String suffix = "@" + provider.getDomain();
+ if (!usernameField.getText().toString().endsWith(suffix)) {
+ s.append(suffix);
+ usernameField.setSelection(usernameField.getText().toString().indexOf('@'));
+ }
+ }
+ }
+ });
+ usernameField.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (actionId == IME_ACTION_DONE
+ || event != null && event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
+ passwordField.requestFocus();
+ return true;
+ }
+ return false;
+ }
+ });
+
+ passwordField.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if(getPassword().length() < 8) {
+ updatePasswordError(getString(R.string.error_not_valid_password_user_message));
+ } else {
+ updatePasswordError(null);
+ }
+ }
+ });
+ passwordField.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (actionId == IME_ACTION_DONE
+ || event != null && event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
+ if (passwordVerificationField.getVisibility() == VISIBLE) {
+ passwordVerificationField.requestFocus();
+ } else {
+ button.performClick();
+ }
+ return true;
+ }
+ return false;
+ }
+ });
+
+ passwordVerificationField.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if(getPassword().equals(getPasswordVerification())) {
+ updateVerificationError(null);
+ } else {
+ updateVerificationError(getString(R.string.password_mismatch));
+ }
+ }
+ });
+ passwordVerificationField.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (actionId == IME_ACTION_DONE
+ || event != null && event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
+ button.performClick();
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+
+ private void hideKeyboard() {
+ InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.hideSoftInputFromWindow(passwordField.getWindowToken(), 0);
+ }
+ }
+
+ private void handleReceivedErrors(Bundle arguments) {
+ if (arguments.containsKey(CREDENTIAL_ERRORS.PASSWORD_INVALID_LENGTH.toString())) {
+ updatePasswordError(getString(R.string.error_not_valid_password_user_message));
+ } else if (arguments.containsKey(CREDENTIAL_ERRORS.RISEUP_WARNING.toString())) {
+ userMessage.setVisibility(VISIBLE);
+ userMessage.setText(R.string.login_riseup_warning);
+ }
+ if (arguments.containsKey(CREDENTIALS_USERNAME)) {
+ String username = arguments.getString(CREDENTIALS_USERNAME);
+ usernameField.setText(username);
+ }
+ if (arguments.containsKey(CREDENTIAL_ERRORS.USERNAME_MISSING.toString())) {
+ updateUsernameError(getString(R.string.username_ask));
+ }
+ if (arguments.containsKey(USER_MESSAGE)) {
+ String userMessageString = arguments.getString(USER_MESSAGE);
+ try {
+ userMessageString = new JSONArray(userMessageString).getString(0);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.N) {
+ userMessage.setText(Html.fromHtml(userMessageString, Html.FROM_HTML_MODE_LEGACY));
+ } else {
+ userMessage.setText(Html.fromHtml(userMessageString));
+ }
+ Linkify.addLinks(userMessage, Linkify.ALL);
+ userMessage.setMovementMethod(LinkMovementMethod.getInstance());
+ userMessage.setVisibility(VISIBLE);
+ } else if (userMessage.getVisibility() != GONE) {
+ userMessage.setVisibility(GONE);
+ }
+
+ if (!usernameField.getText().toString().isEmpty() && passwordField.isFocusable())
+ passwordField.requestFocus();
+
+ mConfigState.setAction(SHOWING_FORM);
+ hideProgressBar();
+ }
+
+ private void successfullyFinished(Provider handledProvider) {
+ provider = handledProvider;
+ Intent resultData = new Intent();
+ resultData.putExtra(Provider.KEY, provider);
+ setResult(RESULT_OK, resultData);
+ finish();
+ }
+
+ //TODO: replace with EipSetupObserver
+ public class ProviderAPIBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "received Broadcast");
+
+ String action = intent.getAction();
+ if (action == null || !action.equalsIgnoreCase(BROADCAST_PROVIDER_API_EVENT)) {
+ return;
+ }
+
+ int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, RESULT_CANCELED);
+ Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY);
+ Provider handledProvider = resultData.getParcelable(PROVIDER_KEY);
+
+ switch (resultCode) {
+ case ProviderAPI.SUCCESSFUL_SIGNUP:
+ String password = resultData.getString(CREDENTIALS_PASSWORD);
+ String username = resultData.getString(CREDENTIALS_USERNAME);
+ login(username, password);
+ break;
+ case ProviderAPI.SUCCESSFUL_LOGIN:
+ downloadVpnCertificate(handledProvider);
+ break;
+ case ProviderAPI.FAILED_LOGIN:
+ case ProviderAPI.FAILED_SIGNUP:
+ handleReceivedErrors((Bundle) intent.getParcelableExtra(BROADCAST_RESULT_KEY));
+ break;
+
+ case ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE:
+ // error handling takes place in MainActivity
+ case ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE:
+ successfullyFinished(handledProvider);
+ break;
+ }
+ }
+ }
+}