2019-02-07 22:39:33 +01:00
|
|
|
package com.beemdevelopment.aegis.ui;
|
2018-02-09 17:31:07 +01:00
|
|
|
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.os.Bundle;
|
|
|
|
import android.view.Menu;
|
|
|
|
import android.view.MenuItem;
|
|
|
|
import android.view.View;
|
|
|
|
import android.widget.Toast;
|
|
|
|
|
2019-10-16 22:16:47 +02:00
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.appcompat.app.ActionBar;
|
|
|
|
import androidx.appcompat.app.AlertDialog;
|
|
|
|
import androidx.biometric.BiometricPrompt;
|
|
|
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
|
2019-04-04 14:07:36 +02:00
|
|
|
import com.beemdevelopment.aegis.R;
|
2019-02-07 22:39:33 +01:00
|
|
|
import com.beemdevelopment.aegis.crypto.KeyStoreHandle;
|
|
|
|
import com.beemdevelopment.aegis.crypto.KeyStoreHandleException;
|
2019-12-25 19:21:34 +01:00
|
|
|
import com.beemdevelopment.aegis.vault.VaultFileCredentials;
|
|
|
|
import com.beemdevelopment.aegis.vault.slots.BiometricSlot;
|
|
|
|
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
|
|
|
import com.beemdevelopment.aegis.vault.slots.Slot;
|
|
|
|
import com.beemdevelopment.aegis.vault.slots.SlotException;
|
|
|
|
import com.beemdevelopment.aegis.vault.slots.SlotList;
|
2019-10-16 22:16:47 +02:00
|
|
|
import com.beemdevelopment.aegis.helpers.BiometricSlotInitializer;
|
|
|
|
import com.beemdevelopment.aegis.helpers.BiometricsHelper;
|
2019-02-07 22:39:33 +01:00
|
|
|
import com.beemdevelopment.aegis.ui.views.SlotAdapter;
|
|
|
|
|
2018-02-09 17:31:07 +01:00
|
|
|
import javax.crypto.Cipher;
|
|
|
|
|
2019-10-16 22:16:47 +02:00
|
|
|
public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Listener {
|
2019-12-25 19:21:34 +01:00
|
|
|
private VaultFileCredentials _creds;
|
2018-02-09 17:31:07 +01:00
|
|
|
private SlotAdapter _adapter;
|
|
|
|
|
2018-06-09 20:23:39 +02:00
|
|
|
private boolean _edited;
|
2018-05-14 21:02:35 +02:00
|
|
|
|
2018-02-09 17:31:07 +01:00
|
|
|
@Override
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
setContentView(R.layout.activity_slots);
|
2018-06-09 20:23:39 +02:00
|
|
|
_edited = false;
|
2018-05-11 15:12:36 +02:00
|
|
|
|
2018-02-09 17:31:07 +01:00
|
|
|
ActionBar bar = getSupportActionBar();
|
|
|
|
bar.setHomeAsUpIndicator(R.drawable.ic_close);
|
|
|
|
bar.setDisplayHomeAsUpEnabled(true);
|
|
|
|
|
2019-10-16 22:16:47 +02:00
|
|
|
findViewById(R.id.button_add_biometric).setOnClickListener(view -> {
|
|
|
|
if (BiometricsHelper.isAvailable(this)) {
|
|
|
|
BiometricSlotInitializer initializer = new BiometricSlotInitializer(SlotManagerActivity.this, new RegisterBiometricsListener());
|
|
|
|
BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder()
|
|
|
|
.setTitle(getString(R.string.add_biometric_slot))
|
|
|
|
.setNegativeButtonText(getString(android.R.string.cancel))
|
|
|
|
.build();
|
|
|
|
initializer.authenticate(info);
|
2019-05-15 22:01:47 +02:00
|
|
|
}
|
2018-11-15 21:23:18 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
findViewById(R.id.button_add_password).setOnClickListener(view -> {
|
2019-10-16 22:16:47 +02:00
|
|
|
Dialogs.showSetPasswordDialog(this, new PasswordListener());
|
2018-02-10 17:20:41 +01:00
|
|
|
});
|
2018-02-09 17:31:07 +01:00
|
|
|
|
|
|
|
// set up the recycler view
|
|
|
|
_adapter = new SlotAdapter(this);
|
|
|
|
RecyclerView slotsView = findViewById(R.id.list_slots);
|
|
|
|
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
|
|
|
|
slotsView.setLayoutManager(layoutManager);
|
|
|
|
slotsView.setAdapter(_adapter);
|
|
|
|
slotsView.setNestedScrollingEnabled(false);
|
|
|
|
|
|
|
|
// load the slots and masterKey
|
2019-12-25 19:21:34 +01:00
|
|
|
_creds = (VaultFileCredentials) getIntent().getSerializableExtra("creds");
|
2018-10-06 22:23:38 +02:00
|
|
|
for (Slot slot : _creds.getSlots()) {
|
2018-02-09 17:31:07 +01:00
|
|
|
_adapter.addSlot(slot);
|
|
|
|
}
|
2018-02-10 17:20:41 +01:00
|
|
|
|
2019-10-16 22:16:47 +02:00
|
|
|
updateBiometricsButton();
|
2018-02-10 17:20:41 +01:00
|
|
|
}
|
|
|
|
|
2019-10-16 22:16:47 +02:00
|
|
|
private void updateBiometricsButton() {
|
|
|
|
// only show the biometrics option if we can get an instance of the biometrics manager
|
2018-02-10 17:20:41 +01:00
|
|
|
// and if none of the slots in the collection has a matching alias in the keystore
|
|
|
|
int visibility = View.VISIBLE;
|
2019-10-16 22:16:47 +02:00
|
|
|
if (BiometricsHelper.isAvailable(this)) {
|
2018-02-13 19:27:40 +01:00
|
|
|
try {
|
|
|
|
KeyStoreHandle keyStore = new KeyStoreHandle();
|
2019-10-16 22:16:47 +02:00
|
|
|
for (BiometricSlot slot : _creds.getSlots().findAll(BiometricSlot.class)) {
|
2018-09-19 00:17:48 +02:00
|
|
|
if (keyStore.containsKey(slot.getUUID().toString())) {
|
2018-02-13 19:27:40 +01:00
|
|
|
visibility = View.GONE;
|
|
|
|
break;
|
|
|
|
}
|
2018-02-10 17:20:41 +01:00
|
|
|
}
|
2018-02-13 19:27:40 +01:00
|
|
|
} catch (KeyStoreHandleException e) {
|
|
|
|
visibility = View.GONE;
|
2018-02-10 17:20:41 +01:00
|
|
|
}
|
2018-02-13 19:27:40 +01:00
|
|
|
} else {
|
2018-02-10 17:20:41 +01:00
|
|
|
visibility = View.GONE;
|
|
|
|
}
|
2019-10-16 22:16:47 +02:00
|
|
|
findViewById(R.id.button_add_biometric).setVisibility(visibility);
|
2018-02-09 17:31:07 +01:00
|
|
|
}
|
|
|
|
|
2018-05-14 21:02:35 +02:00
|
|
|
private void onSave() {
|
2018-02-09 17:31:07 +01:00
|
|
|
Intent intent = new Intent();
|
2018-10-06 22:23:38 +02:00
|
|
|
intent.putExtra("creds", _creds);
|
2018-02-09 17:31:07 +01:00
|
|
|
setResult(RESULT_OK, intent);
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
|
|
|
switch (item.getItemId()) {
|
|
|
|
case android.R.id.home:
|
|
|
|
onBackPressed();
|
2018-05-14 21:02:35 +02:00
|
|
|
break;
|
2018-02-09 17:31:07 +01:00
|
|
|
case R.id.action_save:
|
2018-05-14 21:02:35 +02:00
|
|
|
onSave();
|
|
|
|
break;
|
2018-02-09 17:31:07 +01:00
|
|
|
default:
|
|
|
|
return super.onOptionsItemSelected(item);
|
|
|
|
}
|
2018-05-14 21:02:35 +02:00
|
|
|
|
|
|
|
return true;
|
2018-02-09 17:31:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
|
|
|
getMenuInflater().inflate(R.menu.menu_slots, menu);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-05-14 21:02:35 +02:00
|
|
|
@Override
|
|
|
|
public void onBackPressed() {
|
|
|
|
if (!_edited) {
|
|
|
|
super.onBackPressed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Dialogs.showDiscardDialog(this,
|
|
|
|
(dialog, which) -> onSave(),
|
|
|
|
(dialog, which) -> super.onBackPressed()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-02-09 17:31:07 +01:00
|
|
|
@Override
|
|
|
|
public void onEditSlot(Slot slot) {
|
2018-02-13 13:29:01 +01:00
|
|
|
/*EditText textName = new EditText(this);
|
2018-02-09 17:31:07 +01:00
|
|
|
textName.setHint("Name");
|
|
|
|
|
|
|
|
new AlertDialog.Builder(this)
|
|
|
|
.setTitle("Edit slot name")
|
|
|
|
.setView(textName)
|
|
|
|
.setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
|
|
|
|
String name = textName.getText().toString();
|
2018-05-14 21:02:35 +02:00
|
|
|
_edited = true;
|
2018-02-09 17:31:07 +01:00
|
|
|
})
|
|
|
|
.setNegativeButton(android.R.string.cancel, null)
|
2018-02-13 13:29:01 +01:00
|
|
|
.show();*/
|
2018-02-09 17:31:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onRemoveSlot(Slot slot) {
|
2018-10-06 22:23:38 +02:00
|
|
|
SlotList slots = _creds.getSlots();
|
|
|
|
if (slot instanceof PasswordSlot && slots.findAll(PasswordSlot.class).size() <= 1) {
|
2018-10-09 23:13:51 +02:00
|
|
|
Toast.makeText(this, R.string.password_slot_error, Toast.LENGTH_SHORT).show();
|
2018-02-09 17:31:07 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-15 22:20:31 +01:00
|
|
|
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
|
2018-10-09 23:13:51 +02:00
|
|
|
.setTitle(R.string.remove_slot)
|
|
|
|
.setMessage(R.string.remove_slot_description)
|
2018-02-09 17:31:07 +01:00
|
|
|
.setPositiveButton(android.R.string.yes, (dialog, whichButton) -> {
|
2018-10-06 22:23:38 +02:00
|
|
|
slots.remove(slot);
|
2018-02-09 17:31:07 +01:00
|
|
|
_adapter.removeSlot(slot);
|
2018-05-14 21:02:35 +02:00
|
|
|
_edited = true;
|
2019-10-16 22:16:47 +02:00
|
|
|
updateBiometricsButton();
|
2018-02-09 17:31:07 +01:00
|
|
|
})
|
|
|
|
.setNegativeButton(android.R.string.no, null)
|
2018-11-15 22:20:31 +01:00
|
|
|
.create());
|
2018-02-09 17:31:07 +01:00
|
|
|
}
|
|
|
|
|
2019-10-16 22:16:47 +02:00
|
|
|
private void addSlot(Slot slot) {
|
2018-10-06 22:23:38 +02:00
|
|
|
_creds.getSlots().add(slot);
|
2018-02-09 17:31:07 +01:00
|
|
|
_adapter.addSlot(slot);
|
2018-05-14 21:02:35 +02:00
|
|
|
_edited = true;
|
2019-10-16 22:16:47 +02:00
|
|
|
updateBiometricsButton();
|
2018-02-09 17:31:07 +01:00
|
|
|
}
|
|
|
|
|
2019-10-16 22:16:47 +02:00
|
|
|
private void showSlotError(String error) {
|
|
|
|
Toast.makeText(SlotManagerActivity.this, getString(R.string.adding_new_slot_error) + error, Toast.LENGTH_SHORT).show();
|
|
|
|
}
|
|
|
|
|
|
|
|
private class RegisterBiometricsListener implements BiometricSlotInitializer.Listener {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onInitializeSlot(BiometricSlot slot, Cipher cipher) {
|
|
|
|
try {
|
|
|
|
slot.setKey(_creds.getKey(), cipher);
|
|
|
|
addSlot(slot);
|
|
|
|
} catch (SlotException e) {
|
|
|
|
onSlotInitializationFailed(0, e.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSlotInitializationFailed(int errorCode, @NonNull CharSequence errString) {
|
|
|
|
if (!BiometricsHelper.isCanceled(errorCode)) {
|
|
|
|
showSlotError(errString.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class PasswordListener implements Dialogs.SlotListener {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSlotResult(Slot slot, Cipher cipher) {
|
|
|
|
try {
|
|
|
|
slot.setKey(_creds.getKey(), cipher);
|
|
|
|
} catch (SlotException e) {
|
|
|
|
onException(e);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
addSlot(slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onException(Exception e) {
|
|
|
|
showSlotError(e.toString());
|
|
|
|
}
|
2018-02-09 17:31:07 +01:00
|
|
|
}
|
|
|
|
}
|