mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-05-16 23:12:51 +00:00
Refactor the database classes to be more reusable
This commit is contained in:
parent
571cf20eda
commit
0434513820
18 changed files with 311 additions and 256 deletions
|
@ -25,6 +25,7 @@ import me.impy.aegis.R;
|
|||
import me.impy.aegis.crypto.KeyStoreHandle;
|
||||
import me.impy.aegis.crypto.KeyStoreHandleException;
|
||||
import me.impy.aegis.crypto.MasterKey;
|
||||
import me.impy.aegis.db.DatabaseFileCredentials;
|
||||
import me.impy.aegis.db.slots.FingerprintSlot;
|
||||
import me.impy.aegis.db.slots.PasswordSlot;
|
||||
import me.impy.aegis.db.slots.Slot;
|
||||
|
@ -128,7 +129,7 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
|
|||
private void setKey(MasterKey key) {
|
||||
// send the master key back to the main activity
|
||||
Intent result = new Intent();
|
||||
result.putExtra("key", key);
|
||||
result.putExtra("creds", new DatabaseFileCredentials(key, _slots));
|
||||
setResult(RESULT_OK, result);
|
||||
finish();
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import javax.crypto.SecretKey;
|
|||
|
||||
import me.impy.aegis.Preferences;
|
||||
import me.impy.aegis.R;
|
||||
import me.impy.aegis.crypto.MasterKey;
|
||||
import me.impy.aegis.db.DatabaseFileCredentials;
|
||||
import me.impy.aegis.db.DatabaseFileException;
|
||||
import me.impy.aegis.db.DatabaseManagerException;
|
||||
import me.impy.aegis.db.slots.FingerprintSlot;
|
||||
|
@ -128,9 +128,9 @@ public class IntroActivity extends AppIntro2 implements DerivationTask.Callback
|
|||
}
|
||||
|
||||
// generate the master key
|
||||
MasterKey masterKey = null;
|
||||
DatabaseFileCredentials creds = null;
|
||||
if (cryptType != CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
||||
masterKey = MasterKey.generate();
|
||||
creds = new DatabaseFileCredentials();
|
||||
}
|
||||
|
||||
SlotList slots = null;
|
||||
|
@ -141,10 +141,8 @@ public class IntroActivity extends AppIntro2 implements DerivationTask.Callback
|
|||
throw new RuntimeException();
|
||||
}
|
||||
try {
|
||||
_passwordSlot.setKey(masterKey, _passwordCipher);
|
||||
slots = new SlotList();
|
||||
slots.add(_passwordSlot);
|
||||
_databaseFile.setSlots(slots);
|
||||
_passwordSlot.setKey(creds.getKey(), _passwordCipher);
|
||||
creds.getSlots().add(_passwordSlot);
|
||||
} catch (SlotException e) {
|
||||
setException(e);
|
||||
}
|
||||
|
@ -156,8 +154,8 @@ public class IntroActivity extends AppIntro2 implements DerivationTask.Callback
|
|||
// and add it to the list of slots
|
||||
FingerprintSlot slot = _authenticatedSlide.getFingerSlot();
|
||||
Cipher cipher = _authenticatedSlide.getFingerCipher();
|
||||
slot.setKey(masterKey, cipher);
|
||||
slots.add(slot);
|
||||
slot.setKey(creds.getKey(), cipher);
|
||||
creds.getSlots().add(slot);
|
||||
} catch (SlotException e) {
|
||||
setException(e);
|
||||
return;
|
||||
|
@ -166,11 +164,11 @@ public class IntroActivity extends AppIntro2 implements DerivationTask.Callback
|
|||
|
||||
// finally, save the database
|
||||
try {
|
||||
JSONObject obj = _database.serialize();
|
||||
JSONObject obj = _database.toJson();
|
||||
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
||||
_databaseFile.setContent(obj);
|
||||
} else {
|
||||
_databaseFile.setContent(obj, masterKey);
|
||||
_databaseFile.setContent(obj, creds);
|
||||
}
|
||||
DatabaseManager.save(getApplicationContext(), _databaseFile);
|
||||
} catch (DatabaseManagerException | DatabaseFileException e) {
|
||||
|
@ -180,7 +178,7 @@ public class IntroActivity extends AppIntro2 implements DerivationTask.Callback
|
|||
|
||||
// send the master key back to the main activity
|
||||
Intent result = new Intent();
|
||||
result.putExtra("key", masterKey);
|
||||
result.putExtra("creds", creds);
|
||||
setResult(RESULT_OK, result);
|
||||
|
||||
// skip the intro from now on
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.lang.reflect.UndeclaredThrowableException;
|
|||
|
||||
import me.impy.aegis.AegisApplication;
|
||||
import me.impy.aegis.R;
|
||||
import me.impy.aegis.crypto.MasterKey;
|
||||
import me.impy.aegis.db.DatabaseFileCredentials;
|
||||
import me.impy.aegis.db.DatabaseManagerException;
|
||||
import me.impy.aegis.db.DatabaseEntry;
|
||||
import me.impy.aegis.db.DatabaseManager;
|
||||
|
@ -218,13 +218,13 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
|
||||
MasterKey key = (MasterKey) data.getSerializableExtra("key");
|
||||
unlockDatabase(key);
|
||||
DatabaseFileCredentials creds = (DatabaseFileCredentials) data.getSerializableExtra("creds");
|
||||
unlockDatabase(creds);
|
||||
}
|
||||
|
||||
private void onDecryptResult(int resultCode, Intent intent) {
|
||||
MasterKey key = (MasterKey) intent.getSerializableExtra("key");
|
||||
unlockDatabase(key);
|
||||
DatabaseFileCredentials creds = (DatabaseFileCredentials) intent.getSerializableExtra("creds");
|
||||
unlockDatabase(creds);
|
||||
|
||||
doShortcutActions();
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
}
|
||||
}
|
||||
|
||||
private void unlockDatabase(MasterKey key) {
|
||||
private void unlockDatabase(DatabaseFileCredentials creds) {
|
||||
if (_loaded) {
|
||||
return;
|
||||
}
|
||||
|
@ -371,15 +371,14 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
_db.load();
|
||||
}
|
||||
if (_db.isLocked()) {
|
||||
if (key == null) {
|
||||
if (creds == null) {
|
||||
startAuthActivity();
|
||||
return;
|
||||
} else {
|
||||
_db.unlock(key);
|
||||
_db.unlock(creds);
|
||||
}
|
||||
}
|
||||
} catch (DatabaseManagerException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, "An error occurred while trying to load/decrypt the database", Toast.LENGTH_LONG).show();
|
||||
startAuthActivity();
|
||||
return;
|
||||
|
@ -396,7 +395,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
|
||||
private void startAuthActivity() {
|
||||
Intent intent = new Intent(this, AuthActivity.class);
|
||||
intent.putExtra("slots", _db.getFile().getSlots());
|
||||
intent.putExtra("slots", _db.getFileHeader().getSlots());
|
||||
startActivityForResult(intent, CODE_DECRYPT);
|
||||
}
|
||||
|
||||
|
@ -404,7 +403,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
try {
|
||||
_db.save();
|
||||
} catch (DatabaseManagerException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, "An error occurred while trying to save the database", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
@ -413,7 +411,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
// hide the lock icon if the database is not unlocked
|
||||
if (_menu != null && !_db.isLocked()) {
|
||||
MenuItem item = _menu.findItem(R.id.action_lock);
|
||||
item.setVisible(_db.getFile().isEncrypted());
|
||||
item.setVisible(_db.isEncryptionEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,12 +26,12 @@ import javax.crypto.Cipher;
|
|||
|
||||
import me.impy.aegis.AegisApplication;
|
||||
import me.impy.aegis.R;
|
||||
import me.impy.aegis.crypto.MasterKey;
|
||||
import me.impy.aegis.db.DatabaseEntry;
|
||||
import me.impy.aegis.db.DatabaseFileCredentials;
|
||||
import me.impy.aegis.db.DatabaseFileException;
|
||||
import me.impy.aegis.db.DatabaseManager;
|
||||
import me.impy.aegis.db.DatabaseManagerException;
|
||||
import me.impy.aegis.db.slots.Slot;
|
||||
import me.impy.aegis.db.slots.SlotList;
|
||||
import me.impy.aegis.db.slots.SlotException;
|
||||
import me.impy.aegis.helpers.PermissionHelper;
|
||||
import me.impy.aegis.importers.AegisImporter;
|
||||
|
@ -138,7 +138,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
_encryptionPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (!_db.getFile().isEncrypted()) {
|
||||
if (!_db.isEncryptionEnabled()) {
|
||||
PasswordDialogFragment dialog = new PasswordDialogFragment();
|
||||
// TODO: find a less ugly way to obtain the fragment manager
|
||||
dialog.show(getActivity().getSupportFragmentManager(), null);
|
||||
|
@ -148,8 +148,11 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
.setMessage("Are you sure you want to disable encryption? This will cause the database to be stored in plain text")
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
_db.disableEncryption();
|
||||
saveDatabase();
|
||||
try {
|
||||
_db.disableEncryption();
|
||||
} catch (DatabaseManagerException e) {
|
||||
Toast.makeText(getActivity(), "An error occurred while enabling encryption", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
updateEncryptionPreference();
|
||||
}
|
||||
})
|
||||
|
@ -163,10 +166,8 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
_slotsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
MasterKey masterKey = _db.getMasterKey();
|
||||
Intent intent = new Intent(getActivity(), SlotManagerActivity.class);
|
||||
intent.putExtra("masterKey", masterKey);
|
||||
intent.putExtra("slots", _db.getFile().getSlots());
|
||||
intent.putExtra("creds", _db.getCredentials());
|
||||
startActivityForResult(intent, CODE_SLOTS);
|
||||
return true;
|
||||
}
|
||||
|
@ -249,13 +250,12 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
return;
|
||||
}
|
||||
|
||||
MasterKey key = (MasterKey) data.getSerializableExtra("key");
|
||||
((AegisImporter)_importer).setKey(key);
|
||||
DatabaseFileCredentials creds = (DatabaseFileCredentials) data.getSerializableExtra("creds");
|
||||
((AegisImporter)_importer).setCredentials(creds);
|
||||
|
||||
try {
|
||||
importDatabase(_importer);
|
||||
} catch (DatabaseImporterException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(getActivity(), "An error occurred while trying to parse the file", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
|
@ -269,25 +269,16 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
}
|
||||
|
||||
ByteInputStream stream;
|
||||
InputStream fileStream = null;
|
||||
|
||||
try {
|
||||
fileStream = getActivity().getContentResolver().openInputStream(uri);
|
||||
try (InputStream fileStream = getActivity().getContentResolver().openInputStream(uri)) {
|
||||
stream = ByteInputStream.create(fileStream);
|
||||
} catch (FileNotFoundException e) {
|
||||
Toast.makeText(getActivity(), "Error: File not found", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(getActivity(), "An error occurred while trying to read the file", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
} finally {
|
||||
if (fileStream != null) {
|
||||
try {
|
||||
fileStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -299,7 +290,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
_importer = importer;
|
||||
|
||||
Intent intent = new Intent(getActivity(), AuthActivity.class);
|
||||
intent.putExtra("slots", ((AegisImporter)_importer).getFile().getSlots());
|
||||
intent.putExtra("slots", ((AegisImporter)_importer).getFile().getHeader().getSlots());
|
||||
startActivityForResult(intent, CODE_IMPORT_DECRYPT);
|
||||
return;
|
||||
}
|
||||
|
@ -344,7 +335,6 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
try {
|
||||
filename = _db.export(checked[0]);
|
||||
} catch (DatabaseManagerException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(getActivity(), "An error occurred while trying to export the database", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
@ -355,7 +345,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
Toast.makeText(getActivity(), "The database has been exported to: " + filename, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null);
|
||||
if (_db.getFile().isEncrypted()) {
|
||||
if (_db.isEncryptionEnabled()) {
|
||||
final String[] items = {"Keep the database encrypted"};
|
||||
final boolean[] checkedItems = {true};
|
||||
builder.setMultiChoiceItems(items, checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
|
||||
|
@ -375,8 +365,8 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
return;
|
||||
}
|
||||
|
||||
SlotList slots = (SlotList) data.getSerializableExtra("slots");
|
||||
_db.getFile().setSlots(slots);
|
||||
DatabaseFileCredentials creds = (DatabaseFileCredentials) data.getSerializableExtra("creds");
|
||||
_db.setCredentials(creds);
|
||||
saveDatabase();
|
||||
}
|
||||
|
||||
|
@ -384,7 +374,6 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
try {
|
||||
_db.save();
|
||||
} catch (DatabaseManagerException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(getActivity(), "An error occurred while trying to save the database", Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
@ -394,19 +383,17 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
|
||||
@Override
|
||||
public void onSlotResult(Slot slot, Cipher cipher) {
|
||||
MasterKey masterKey = MasterKey.generate();
|
||||
DatabaseFileCredentials creds = new DatabaseFileCredentials();
|
||||
|
||||
SlotList slots = new SlotList();
|
||||
try {
|
||||
slot.setKey(masterKey, cipher);
|
||||
} catch (SlotException e) {
|
||||
slot.setKey(creds.getKey(), cipher);
|
||||
creds.getSlots().add(slot);
|
||||
_db.enableEncryption(creds);
|
||||
} catch (DatabaseManagerException | SlotException e) {
|
||||
onException(e);
|
||||
return;
|
||||
}
|
||||
slots.add(slot);
|
||||
_db.enableEncryption(masterKey, slots);
|
||||
|
||||
saveDatabase();
|
||||
updateEncryptionPreference();
|
||||
}
|
||||
|
||||
|
@ -417,7 +404,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat implements Pas
|
|||
}
|
||||
|
||||
private void updateEncryptionPreference() {
|
||||
boolean encrypted = _db.getFile().isEncrypted();
|
||||
boolean encrypted = _db.isEncryptionEnabled();
|
||||
_encryptionPreference.setChecked(encrypted, true);
|
||||
_slotsPreference.setEnabled(encrypted);
|
||||
}
|
||||
|
|
|
@ -110,10 +110,7 @@ public class ScannerActivity extends AegisActivity implements ZXingScannerView.R
|
|||
// parse google auth uri
|
||||
Uri uri = Uri.parse(rawResult.getText());
|
||||
GoogleAuthInfo info = GoogleAuthInfo.parseUri(uri);
|
||||
|
||||
DatabaseEntry entry = new DatabaseEntry(info.getOtpInfo());
|
||||
entry.setIssuer(info.getIssuer());
|
||||
entry.setName(info.getAccountName());
|
||||
DatabaseEntry entry = new DatabaseEntry(info);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("entry", entry);
|
||||
|
|
|
@ -16,7 +16,7 @@ import javax.crypto.Cipher;
|
|||
import me.impy.aegis.R;
|
||||
import me.impy.aegis.crypto.KeyStoreHandle;
|
||||
import me.impy.aegis.crypto.KeyStoreHandleException;
|
||||
import me.impy.aegis.crypto.MasterKey;
|
||||
import me.impy.aegis.db.DatabaseFileCredentials;
|
||||
import me.impy.aegis.db.slots.FingerprintSlot;
|
||||
import me.impy.aegis.db.slots.PasswordSlot;
|
||||
import me.impy.aegis.db.slots.Slot;
|
||||
|
@ -29,8 +29,7 @@ import me.impy.aegis.ui.views.SlotAdapter;
|
|||
import me.impy.aegis.ui.dialogs.SlotDialogFragment;
|
||||
|
||||
public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Listener, SlotDialogFragment.Listener {
|
||||
private MasterKey _masterKey;
|
||||
private SlotList _slots;
|
||||
private DatabaseFileCredentials _creds;
|
||||
private SlotAdapter _adapter;
|
||||
|
||||
private boolean _edited;
|
||||
|
@ -59,9 +58,8 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
slotsView.setNestedScrollingEnabled(false);
|
||||
|
||||
// load the slots and masterKey
|
||||
_masterKey = (MasterKey) getIntent().getSerializableExtra("masterKey");
|
||||
_slots = (SlotList) getIntent().getSerializableExtra("slots");
|
||||
for (Slot slot : _slots) {
|
||||
_creds = (DatabaseFileCredentials) getIntent().getSerializableExtra("creds");
|
||||
for (Slot slot : _creds.getSlots()) {
|
||||
_adapter.addSlot(slot);
|
||||
}
|
||||
|
||||
|
@ -75,7 +73,7 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
if (FingerprintHelper.getManager(this) != null) {
|
||||
try {
|
||||
KeyStoreHandle keyStore = new KeyStoreHandle();
|
||||
for (FingerprintSlot slot : _slots.findAll(FingerprintSlot.class)) {
|
||||
for (FingerprintSlot slot : _creds.getSlots().findAll(FingerprintSlot.class)) {
|
||||
if (keyStore.containsKey(slot.getUUID().toString())) {
|
||||
visibility = View.GONE;
|
||||
break;
|
||||
|
@ -92,7 +90,7 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
|
||||
private void onSave() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("slots", _slots);
|
||||
intent.putExtra("creds", _creds);
|
||||
setResult(RESULT_OK, intent);
|
||||
finish();
|
||||
}
|
||||
|
@ -150,7 +148,8 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
|
||||
@Override
|
||||
public void onRemoveSlot(Slot slot) {
|
||||
if (slot instanceof PasswordSlot && _slots.findAll(PasswordSlot.class).size() <= 1) {
|
||||
SlotList slots = _creds.getSlots();
|
||||
if (slot instanceof PasswordSlot && slots.findAll(PasswordSlot.class).size() <= 1) {
|
||||
Toast.makeText(this, "You must have at least one password slot", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
@ -159,7 +158,7 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
.setTitle("Remove slot")
|
||||
.setMessage("Are you sure you want to remove this slot?")
|
||||
.setPositiveButton(android.R.string.yes, (dialog, whichButton) -> {
|
||||
_slots.remove(slot);
|
||||
slots.remove(slot);
|
||||
_adapter.removeSlot(slot);
|
||||
_edited = true;
|
||||
updateFingerprintButton();
|
||||
|
@ -171,13 +170,13 @@ public class SlotManagerActivity extends AegisActivity implements SlotAdapter.Li
|
|||
@Override
|
||||
public void onSlotResult(Slot slot, Cipher cipher) {
|
||||
try {
|
||||
slot.setKey(_masterKey, cipher);
|
||||
slot.setKey(_creds.getKey(), cipher);
|
||||
} catch (SlotException e) {
|
||||
onException(e);
|
||||
return;
|
||||
}
|
||||
|
||||
_slots.add(slot);
|
||||
_creds.getSlots().add(slot);
|
||||
_adapter.addSlot(slot);
|
||||
_edited = true;
|
||||
updateFingerprintButton();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue