org.benetech.secureapp.activities.CreatePassphraseActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.benetech.secureapp.activities.CreatePassphraseActivity.java

Source

/*
 * The Martus(tm) free, social justice documentation and
 * monitoring software. Copyright (C) 2016, Beneficent
 * Technology, Inc. (Benetech).
 *
 * Martus is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later
 * version with the additions and exceptions described in the
 * accompanying Martus license file entitled "license.txt".
 *
 * It is distributed WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, including warranties of fitness of purpose or
 * merchantability.  See the accompanying Martus License and
 * GPL license for more details on the required license terms
 * for this software.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 */

package org.benetech.secureapp.activities;

import android.app.Application;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.iangclifton.android.floatlabel.FloatLabel;

import org.apache.commons.io.FileUtils;
import org.benetech.secureapp.R;
import org.benetech.secureapp.application.AppConfig;
import org.benetech.secureapp.tasks.CreateMartusCryptoKeyPairCallback;
import org.benetech.secureapp.tasks.CreateMartusCryptoKeyPairTask;
import org.benetech.secureapp.utilities.Utility;
import org.martus.common.crypto.MartusSecurity;
import org.odk.collect.android.application.Collect;

import java.io.File;
import java.security.GeneralSecurityException;
import java.util.Arrays;

import info.guardianproject.cacheword.Wiper;

/**
 * Created by animal@martus.org on 8/21/14.
 */

public class CreatePassphraseActivity extends AbstractLoginActivity implements TextWatcher {

    private static final String TAG = "CreatePassphrase";
    private static final int MIN_PASSPHRASE_LENGTH = 8;
    private static final int NO_ERRORS_FOUND_MESSAGE_ID = -1;
    private FloatLabel passphraseEditField;
    private FloatLabel passphraseConfirmationEditField;
    private Button createAccountButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(org.benetech.secureapp.R.layout.create_account);

        passphraseEditField = (FloatLabel) findViewById(org.benetech.secureapp.R.id.passphrase_edit_field);
        passphraseConfirmationEditField = (FloatLabel) findViewById(
                org.benetech.secureapp.R.id.passphrase_confirm_edit_field);
        createAccountButton = (Button) findViewById(org.benetech.secureapp.R.id.create_account_button);
        createAccountButton.setEnabled(false);

        Util.setupFloatingLabelEditTextForPassword(passphraseEditField.getEditText());
        Util.setupFloatingLabelEditTextForPassword(passphraseConfirmationEditField.getEditText());

        passphraseConfirmationEditField.getEditText().addTextChangedListener(this);
        passphraseEditField.getEditText().addTextChangedListener(this);

        safelyClearOdkDbFilesFromPreviousAccount();
    }

    private void safelyClearOdkDbFilesFromPreviousAccount() {
        try {
            clearOdkDbFilesFromPreviousAccount();
        } catch (Exception e) {
            Log.e(TAG, e.getMessage(), e);
            Toast.makeText(getApplicationContext(),
                    getString(org.benetech.secureapp.R.string.error_cleaning_up_odk_folders), Toast.LENGTH_LONG)
                    .show();
        }
    }

    private void clearOdkDbFilesFromPreviousAccount() throws Exception {
        String externalStorageStatus = Environment.getExternalStorageState();
        final boolean isStorageAvailable = externalStorageStatus.equals(Environment.MEDIA_MOUNTED);
        if (!isStorageAvailable)
            throw new Exception(Collect.getInstance().getString(org.odk.collect.android.R.string.sdcard_unmounted,
                    externalStorageStatus));

        String[] odkPathsToDelete = { Collect.ODK_ROOT, Collect.FORMS_PATH, Collect.INSTANCES_PATH,
                Collect.CACHE_PATH, Collect.METADATA_PATH, };
        for (String dirPath : odkPathsToDelete) {
            File odkDirToDelete = new File(dirPath);
            FileUtils.deleteDirectory(odkDirToDelete);
            if (odkDirToDelete.exists())
                throw new Exception(
                        getString(R.string.error_message_could_not_clear_odk_folders_from_prvious_account));
            else
                Log.i(TAG, getString(R.string.error_message_odk_folders_deleted_as_part_of_cleanup,
                        odkDirToDelete.getAbsolutePath()));
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        passphraseEditField.getEditText().setText("");
        passphraseConfirmationEditField.getEditText().setText("");
    }

    public void createAccount(View view) {
        int errorMessageId = getPossibleValidErrorMessage();
        if (errorMessageId != NO_ERRORS_FOUND_MESSAGE_ID) {
            clearTextFields();
            Toast.makeText(getApplicationContext(), getString(errorMessageId), Toast.LENGTH_SHORT).show();
            return;
        }

        char[] passphrase = passphraseEditField.getEditText().getText().toString().toCharArray();
        try {
            getCacheWordActivityHandler().setPassphrase(passphrase);
        } catch (GeneralSecurityException e) {
            Log.e(TAG, getString(R.string.error_message_cacheword_initialization_failed), e);
        } finally {
            Wiper.wipe(passphrase);
        }
    }

    private int getPossibleValidErrorMessage() {
        if (!doPassPhrasesMatch())
            return org.benetech.secureapp.R.string.settings_pwd_not_equal;

        if (!isValidPassPhraseLength())
            return org.benetech.secureapp.R.string.error_incorrect_passphrase;

        if (!containsOnlyValidChars())
            return org.benetech.secureapp.R.string.error_message_invalid_chars;

        return NO_ERRORS_FOUND_MESSAGE_ID;
    }

    private boolean containsOnlyValidChars() {
        char[] passPhrase = getPassphraseAsCharArray();
        try {
            for (int index = 0; index < passPhrase.length; ++index) {
                char charToValidate = passPhrase[index];
                if (!isCharAllowed(charToValidate)) {
                    return false;
                }
            }

            return true;
        } finally {
            Wiper.wipe(passPhrase);
        }
    }

    private boolean isCharAllowed(char charToValidate) {
        if (charToValidate == ' ')
            return false;

        return true;
    }

    private void clearTextFields() {
        getPassPhraseTextField().setText("");
        passphraseConfirmationEditField.getEditText().setText("");
        passphraseEditField.requestFocus();
    }

    private boolean doPassPhrasesMatch() {
        char[] passPhrase = getPassphraseAsCharArray();
        char[] confirmationPassphrase = getConfirmationPassphraseCharArray();
        try {
            return Arrays.equals(passPhrase, confirmationPassphrase);
        } finally {
            Wiper.wipe(passPhrase);
            Wiper.wipe(confirmationPassphrase);
        }
    }

    private boolean isValidPassPhraseLength() {
        if (getPassPhraseTextField().length() >= MIN_PASSPHRASE_LENGTH)
            return true;

        return false;
    }

    @Override
    public void onCacheWordLocked() {
        lockTextView(getPassPhraseTextField());
        lockTextView(passphraseConfirmationEditField.getEditText());
    }

    @Override
    protected TextView getPassPhraseTextField() {
        return passphraseEditField.getEditText();
    }

    private char[] getPassphraseAsCharArray() {
        return Utility.convertToCharArray(getPassPhraseTextField().getText());
    }

    private char[] getConfirmationPassphraseCharArray() {
        return Utility.convertToCharArray(passphraseConfirmationEditField.getEditText().getText());
    }

    @Override
    protected String getLogTag() {
        return TAG;
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        //do nothing
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // do nothing
    }

    @Override
    public void afterTextChanged(Editable s) {
        char[] password = getPassphraseAsCharArray();
        char[] confirmPassword = getConfirmationPassphraseCharArray();
        if (password.length < 8) {
            passphraseEditField.getEditText().setError(getString(org.benetech.secureapp.R.string.invalid_password));
            return;
        }
        if (Arrays.equals(password, confirmPassword)) {
            createAccountButton.setEnabled(true);
        } else {
            passphraseConfirmationEditField.getEditText()
                    .setError(getString(org.benetech.secureapp.R.string.settings_pwd_not_equal));
        }
    }

    @Override
    protected void postMountStorageExecute() {
        dismissProgressDialog();
        if (getMartusCrypto(getApplication()).hasKeyPair())
            return;

        showProgressDialog(getString(R.string.progress_dialog_message_creating_martus_crytpo_keypair));
        char[] passphrase = passphraseEditField.getEditText().getText().toString().toCharArray();
        try {
            final AsyncTask<Object, Void, Boolean> createAccountTask = new CreateMartusCryptoKeyPairTask(
                    getMartusCrypto(getApplication()), mCreateMartusCryptoKeyPairCallback, getSettings());

            char[] pw = Utility.convertToCharArray(getCacheWordActivityHandler().getEncryptionKey());
            createAccountTask.execute(new Object[] { pw });
        } catch (Exception e) {
            Log.e("uploadForm", getString(R.string.error_message_failed_to_create_account), e);
        } finally {
            Wiper.wipe(passphrase);
        }
    }

    private MartusSecurity getMartusCrypto(Application app) {
        return AppConfig.getInstance(app).getCrypto();
    }

    private void showKeyPairErrorMessage() {
        Util.showErrorMessage(this, getString(org.benetech.secureapp.R.string.keypair_creation_failed));
    }

    private void startSetupAccountActivity() {
        Intent intent = new Intent(this, AccountInformationActivity.class);
        startActivity(intent);
        finish();
    }

    /** Callback for CreateMartusCryptoKeyPairTask */
    private CreateMartusCryptoKeyPairCallback mCreateMartusCryptoKeyPairCallback = new CreateMartusCryptoKeyPairCallback() {
        @Override
        public void onCreateKeyPairError() {
            showKeyPairErrorMessage();
            throw new RuntimeException(getString(R.string.error_message_could_not_create_martus_crypto_key_pair));
        }

        @Override
        public void onCreateKeyPairSuccess() {
            dismissProgressDialog();
            startSetupAccountActivity();
        }
    };
}