package de.pinyto.ctSESAM;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.TextView;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class MainActivity extends AppCompatActivity {
static final String syncAppName = "de.pinyto.ctSESAMsync";
static final String syncServiceName = "SyncService";
Messenger mService = null;
boolean mBound;
private PasswordSettingsManager settingsManager;
private KgkManager kgkManager;
private PasswordGenerator passwordGenerator;
private boolean showSettings = false;
private boolean showPassword = false;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
mService = null;
mBound = false;
}
};
public MainActivity getActivity() {
return this;
}
public void setPasswordGenerator(PasswordGenerator generator) {
this.passwordGenerator = generator;
}
private void updateView() {
Button generateButton = (Button) findViewById(R.id.generatorButton);
TextView passwordHeading = (TextView) findViewById(R.id.textViewPasswordHeading);
TextView password = (TextView) findViewById(R.id.textViewPassword);
if (this.showSettings) {
if (this.showPassword) {
generateButton.setVisibility(View.INVISIBLE);
passwordHeading.setVisibility(View.VISIBLE);
password.setVisibility(View.VISIBLE);
} else {
generateButton.setVisibility(View.VISIBLE);
passwordHeading.setVisibility(View.INVISIBLE);
password.setVisibility(View.INVISIBLE);
}
} else {
generateButton.setVisibility(View.INVISIBLE);
passwordHeading.setVisibility(View.INVISIBLE);
password.setVisibility(View.INVISIBLE);
}
}
private void setDomainFieldFromClipboard() {
ClipboardManager clipboard =
(ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard.hasPrimaryClip()) {
ClipData clipDataCurrent = clipboard.getPrimaryClip();
CharSequence pasteData = clipDataCurrent.getItemAt(0).getText();
if (pasteData != null) {
AutoCompleteTextView autoCompleteTextViewDomain =
(AutoCompleteTextView) findViewById(R.id.autoCompleteTextViewDomain);
autoCompleteTextViewDomain.setText(DomainExtractor.extract(pasteData.toString()));
}
}
}
public void generatePassword() {
AutoCompleteTextView autoCompleteTextViewDomain =
(AutoCompleteTextView) findViewById(R.id.autoCompleteTextViewDomain);
String domainStr = autoCompleteTextViewDomain.getText().toString();
byte[] domain = UTF8.encode(autoCompleteTextViewDomain.getText());
EditText editTextUsername =
(EditText) findViewById(R.id.editTextUsername);
TextView textViewPassword = (TextView) findViewById(R.id.textViewPassword);
byte[] username = UTF8.encode(editTextUsername.getText());
PasswordSetting setting = this.settingsManager.getSetting(domainStr);
if (this.kgkManager.hasKgk()) {
if (!setting.hasLegacyPassword()) {
if (this.passwordGenerator == null) {
GeneratePasswordTask generatePasswordTask = new GeneratePasswordTask(this);
if (setting.getIterations() <= 0) {
setting.setIterations(4096);
}
generatePasswordTask.execute(
domain,
username,
kgkManager.getKgk(),
setting.getSalt(),
ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN)
.putInt(setting.getIterations()).array());
} else {
this.settingsManager.setSetting(setting);
this.settingsManager.storeLocalSettings(this.kgkManager);
textViewPassword.setText(this.passwordGenerator.getPassword(setting));
this.showPassword = true;
this.updateView();
this.invalidateOptionsMenu();
// load settings because the domain might be new
ArrayAdapter<String> adapter = new ArrayAdapter<>(getBaseContext(),
android.R.layout.simple_dropdown_item_1line,
this.settingsManager.getDomainList());
autoCompleteTextViewDomain.setAdapter(adapter);
}
}
} else {
EditText editTextMasterPassword =
(EditText) findViewById(R.id.editTextMasterPassword);
byte[] password = UTF8.encode(editTextMasterPassword.getText());
CreateKgkAndPasswordTask createKgkAndPasswordTask = new CreateKgkAndPasswordTask(
this,
setting.getIterations(),
this.kgkManager,
this.settingsManager);
createKgkAndPasswordTask.execute(password);
}
if (setting.hasLegacyPassword()) {
textViewPassword.setText(setting.getLegacyPassword());
this.showPassword = true;
this.updateView();
this.invalidateOptionsMenu();
}
}
private void clearMasterPassword() {
EditText editTextMasterPassword = (EditText) findViewById(R.id.editTextMasterPassword);
Editable password = editTextMasterPassword.getText();
CharSequence zero = "0";
for (int i = 0; i < password.length(); i++) {
password.replace(i, i+1, zero);
}
editTextMasterPassword.setText("", TextView.BufferType.EDITABLE);
}
private void setToNotGenerated() {
this.passwordGenerator = null;
invalidateOptionsMenu();
TextView textViewPassword = (TextView) findViewById(R.id.textViewPassword);
textViewPassword.setText("");
}
private void loadSettings() {
AutoCompleteTextView autoCompleteTextViewDomain =
(AutoCompleteTextView) findViewById(R.id.autoCompleteTextViewDomain);
String domain = autoCompleteTextViewDomain.getText().toString();
EditText editTextUsername =
(EditText) findViewById(R.id.editTextUsername);
PasswordSetting passwordSetting = settingsManager.getSetting(domain);
this.showSettings = domain.length() > 0;
editTextUsername.setText(passwordSetting.getUsername());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
kgkManager = new KgkManager(getBaseContext());
settingsManager = new PasswordSettingsManager(getBaseContext());
setContentView(R.layout.activity_main);
setDomainFieldFromClipboard();
EditText editTextMasterPassword = (EditText) findViewById(R.id.editTextMasterPassword);
editTextMasterPassword.setText("", TextView.BufferType.EDITABLE);
setToNotGenerated();
clearMasterPassword();
updateView();
editTextMasterPassword.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void afterTextChanged(Editable editable) {
setToNotGenerated();
}
});
AutoCompleteTextView autoCompleteTextViewDomain =
(AutoCompleteTextView) findViewById(R.id.autoCompleteTextViewDomain);
autoCompleteTextViewDomain.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void afterTextChanged(Editable editable) {
setToNotGenerated();
showSettings = editable.length() > 0;
showPassword = false;
for (String domain : settingsManager.getDomainList()) {
if (domain.contentEquals(editable)) {
loadSettings();
generatePassword();
showPassword = true;
break;
}
}
updateView();
}
});
autoCompleteTextViewDomain.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean hasFocus) {
if (!kgkManager.hasKgk()) {
EditText editTextMasterPassword =
(EditText) findViewById(R.id.editTextMasterPassword);
byte[] password = UTF8.encode(editTextMasterPassword.getText());
if (kgkManager.gelLocalKgkBlock().length == 112) {
TextView loadingMessage =
(TextView) findViewById(R.id.textViewDecryptionMessage);
loadingMessage.setText(getString(R.string.loading));
LoadLocalSettingsTask loadLocalSettingsTask = new LoadLocalSettingsTask(
getActivity(),
kgkManager,
settingsManager);
loadLocalSettingsTask.execute(password, kgkManager.getKgkCrypterSalt());
} else {
kgkManager.storeSalt(Crypter.createSalt());
CreateNewKgkTask createNewKgkTask = new CreateNewKgkTask(getActivity(),
kgkManager, settingsManager);
createNewKgkTask.execute(password, kgkManager.getKgkCrypterSalt());
}
}
if (!hasFocus && kgkManager.hasKgk()) {
loadSettings();
}
}
});
autoCompleteTextViewDomain.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
loadSettings();
}
});
Button generateButton = (Button) findViewById(R.id.generatorButton);
generateButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
generatePassword();
}
});
}
private boolean isAppInstalled(String packageName) {
PackageManager pm = getPackageManager();
boolean installed;
try {
pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
installed = true;
} catch (PackageManager.NameNotFoundException e) {
installed = false;
}
return installed;
}
@Override
protected void onStart() {
super.onStart();
if (isAppInstalled(syncAppName)) {
// Bind to the service
Intent intent = new Intent();
intent.setComponent(new ComponentName(
syncAppName,
syncAppName + "." + syncServiceName));
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
invalidateOptionsMenu();
}
@Override
protected void onPause() {
setToNotGenerated();
clearMasterPassword();
super.onPause();
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main_actions, menu);
MenuItem copyItem = menu.findItem(R.id.action_copy);
copyItem.setVisible(this.passwordGenerator != null);
MenuItem syncItem = menu.findItem(R.id.action_sync);
EditText editTextMasterPassword = (EditText) findViewById(R.id.editTextMasterPassword);
syncItem.setVisible(
isAppInstalled(syncAppName) &&
(editTextMasterPassword.getText().length() > 0));
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_copy) {
TextView textViewPassword = (TextView) findViewById(R.id.textViewPassword);
ClipData clipDataPassword = ClipData.newPlainText(
"password",
textViewPassword.getText()
);
ClipboardManager clipboard =
(ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(clipDataPassword);
return true;
}
if (id == R.id.action_sync) {
if (!mBound) {
Log.d("Sync error", "Sync service is not bound. This button should not be visible.");
return true;
}
Message msg = Message.obtain(null, SyncResponseHandler.REQUEST_SYNC, 0, 0);
msg.replyTo = new Messenger(new SyncResponseHandler(
this,
kgkManager,
settingsManager,
mService,
mBound));
try {
mService.send(msg);
} catch (RemoteException e) {
Log.d("Sync error", "Could not send message to sync service.");
e.printStackTrace();
}
return true;
}
return super.onOptionsItemSelected(item);
}
}