mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-05-14 22:12:55 +00:00
Merge pull request #1294 from alexbakker/load-vaultfile
Load vault file on demand instead of juggling it around in-memory
This commit is contained in:
commit
2d0e201060
5 changed files with 53 additions and 93 deletions
|
@ -1,7 +1,6 @@
|
||||||
package com.beemdevelopment.aegis;
|
package com.beemdevelopment.aegis;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@ -32,11 +31,10 @@ public class PanicTriggerTest extends AegisTest {
|
||||||
@Test
|
@Test
|
||||||
public void testPanicTriggerDisabled() {
|
public void testPanicTriggerDisabled() {
|
||||||
assertFalse(_prefs.isPanicTriggerEnabled());
|
assertFalse(_prefs.isPanicTriggerEnabled());
|
||||||
|
assertTrue(_vaultManager.isVaultLoaded());
|
||||||
launchPanic();
|
launchPanic();
|
||||||
assertTrue(_vaultManager.isVaultLoaded());
|
assertTrue(_vaultManager.isVaultLoaded());
|
||||||
_vaultManager.getVault();
|
_vaultManager.getVault();
|
||||||
assertFalse(_vaultManager.isVaultFileLoaded());
|
|
||||||
assertNull(_vaultManager.getVaultFileError());
|
|
||||||
assertTrue(VaultRepository.fileExists(getApp()));
|
assertTrue(VaultRepository.fileExists(getApp()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,11 +42,10 @@ public class PanicTriggerTest extends AegisTest {
|
||||||
public void testPanicTriggerEnabled() {
|
public void testPanicTriggerEnabled() {
|
||||||
_prefs.setIsPanicTriggerEnabled(true);
|
_prefs.setIsPanicTriggerEnabled(true);
|
||||||
assertTrue(_prefs.isPanicTriggerEnabled());
|
assertTrue(_prefs.isPanicTriggerEnabled());
|
||||||
|
assertTrue(_vaultManager.isVaultLoaded());
|
||||||
launchPanic();
|
launchPanic();
|
||||||
assertFalse(_vaultManager.isVaultLoaded());
|
assertFalse(_vaultManager.isVaultLoaded());
|
||||||
assertThrows(IllegalStateException.class, () -> _vaultManager.getVault());
|
assertThrows(IllegalStateException.class, () -> _vaultManager.getVault());
|
||||||
assertFalse(_vaultManager.isVaultFileLoaded());
|
|
||||||
assertNull(_vaultManager.getVaultFileError());
|
|
||||||
assertFalse(VaultRepository.fileExists(getApp()));
|
assertFalse(VaultRepository.fileExists(getApp()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||||
import com.beemdevelopment.aegis.ui.tasks.PasswordSlotDecryptTask;
|
import com.beemdevelopment.aegis.ui.tasks.PasswordSlotDecryptTask;
|
||||||
import com.beemdevelopment.aegis.vault.VaultFile;
|
import com.beemdevelopment.aegis.vault.VaultFile;
|
||||||
import com.beemdevelopment.aegis.vault.VaultFileCredentials;
|
import com.beemdevelopment.aegis.vault.VaultFileCredentials;
|
||||||
|
import com.beemdevelopment.aegis.vault.VaultRepository;
|
||||||
import com.beemdevelopment.aegis.vault.VaultRepositoryException;
|
import com.beemdevelopment.aegis.vault.VaultRepositoryException;
|
||||||
import com.beemdevelopment.aegis.vault.slots.BiometricSlot;
|
import com.beemdevelopment.aegis.vault.slots.BiometricSlot;
|
||||||
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
||||||
|
@ -53,7 +54,9 @@ public class AuthActivity extends AegisActivity {
|
||||||
|
|
||||||
private EditText _textPassword;
|
private EditText _textPassword;
|
||||||
|
|
||||||
|
private VaultFile _vaultFile;
|
||||||
private SlotList _slots;
|
private SlotList _slots;
|
||||||
|
|
||||||
private SecretKey _bioKey;
|
private SecretKey _bioKey;
|
||||||
private BiometricSlot _bioSlot;
|
private BiometricSlot _bioSlot;
|
||||||
private BiometricPrompt _bioPrompt;
|
private BiometricPrompt _bioPrompt;
|
||||||
|
@ -103,17 +106,17 @@ public class AuthActivity extends AegisActivity {
|
||||||
_inhibitBioPrompt = savedInstanceState.getBoolean("inhibitBioPrompt", false);
|
_inhibitBioPrompt = savedInstanceState.getBoolean("inhibitBioPrompt", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_vaultManager.getVaultFileError() != null) {
|
try {
|
||||||
Dialogs.showErrorDialog(this, R.string.vault_load_error, _vaultManager.getVaultFileError(), (dialog, which) -> {
|
_vaultFile = VaultRepository.readVaultFile(this);
|
||||||
|
} catch (VaultRepositoryException e) {
|
||||||
|
Dialogs.showErrorDialog(this, R.string.vault_load_error, e, (dialog, which) -> {
|
||||||
getOnBackPressedDispatcher().onBackPressed();
|
getOnBackPressedDispatcher().onBackPressed();
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
VaultFile vaultFile = _vaultManager.getVaultFile();
|
|
||||||
_slots = vaultFile.getHeader().getSlots();
|
|
||||||
|
|
||||||
// only show the biometric prompt if the api version is new enough, permission is granted, a scanner is found and a biometric slot is found
|
// only show the biometric prompt if the api version is new enough, permission is granted, a scanner is found and a biometric slot is found
|
||||||
|
_slots = _vaultFile.getHeader().getSlots();
|
||||||
if (_slots.has(BiometricSlot.class) && BiometricsHelper.isAvailable(this)) {
|
if (_slots.has(BiometricSlot.class) && BiometricsHelper.isAvailable(this)) {
|
||||||
boolean invalidated = false;
|
boolean invalidated = false;
|
||||||
|
|
||||||
|
@ -281,7 +284,7 @@ public class AuthActivity extends AegisActivity {
|
||||||
VaultFileCredentials creds = new VaultFileCredentials(key, _slots);
|
VaultFileCredentials creds = new VaultFileCredentials(key, _slots);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_vaultManager.unlock(creds);
|
_vaultManager.loadFrom(_vaultFile, creds);
|
||||||
if (isSlotRepaired) {
|
if (isSlotRepaired) {
|
||||||
saveAndBackupVault();
|
saveAndBackupVault();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@ import com.beemdevelopment.aegis.ui.slides.DoneSlide;
|
||||||
import com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide;
|
import com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide;
|
||||||
import com.beemdevelopment.aegis.ui.slides.SecuritySetupSlide;
|
import com.beemdevelopment.aegis.ui.slides.SecuritySetupSlide;
|
||||||
import com.beemdevelopment.aegis.ui.slides.WelcomeSlide;
|
import com.beemdevelopment.aegis.ui.slides.WelcomeSlide;
|
||||||
|
import com.beemdevelopment.aegis.vault.VaultFile;
|
||||||
import com.beemdevelopment.aegis.vault.VaultFileCredentials;
|
import com.beemdevelopment.aegis.vault.VaultFileCredentials;
|
||||||
|
import com.beemdevelopment.aegis.vault.VaultRepository;
|
||||||
import com.beemdevelopment.aegis.vault.VaultRepositoryException;
|
import com.beemdevelopment.aegis.vault.VaultRepositoryException;
|
||||||
import com.beemdevelopment.aegis.vault.slots.BiometricSlot;
|
import com.beemdevelopment.aegis.vault.slots.BiometricSlot;
|
||||||
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
||||||
|
@ -102,8 +104,17 @@ public class IntroActivity extends IntroBaseActivity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
VaultFile vaultFile;
|
||||||
try {
|
try {
|
||||||
_vaultManager.load(creds);
|
vaultFile = VaultRepository.readVaultFile(this);
|
||||||
|
} catch (VaultRepositoryException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Dialogs.showErrorDialog(this, R.string.vault_load_error, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_vaultManager.loadFrom(vaultFile, creds);
|
||||||
} catch (VaultRepositoryException e) {
|
} catch (VaultRepositoryException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
Dialogs.showErrorDialog(this, R.string.vault_load_error, e);
|
Dialogs.showErrorDialog(this, R.string.vault_load_error, e);
|
||||||
|
|
|
@ -54,6 +54,9 @@ import com.beemdevelopment.aegis.ui.tasks.QrDecodeTask;
|
||||||
import com.beemdevelopment.aegis.ui.views.EntryListView;
|
import com.beemdevelopment.aegis.ui.views.EntryListView;
|
||||||
import com.beemdevelopment.aegis.util.TimeUtils;
|
import com.beemdevelopment.aegis.util.TimeUtils;
|
||||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||||
|
import com.beemdevelopment.aegis.vault.VaultFile;
|
||||||
|
import com.beemdevelopment.aegis.vault.VaultRepository;
|
||||||
|
import com.beemdevelopment.aegis.vault.VaultRepositoryException;
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
@ -658,11 +661,32 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_vaultManager.isVaultLoaded() && !_vaultManager.isVaultFileLoaded()) {
|
// If the vault is not loaded yet, try to load it now in case it's plain text
|
||||||
Dialogs.showErrorDialog(this, R.string.vault_load_error, _vaultManager.getVaultFileError(), (dialog1, which) -> finish());
|
if (!_vaultManager.isVaultLoaded()) {
|
||||||
|
VaultFile vaultFile;
|
||||||
|
try {
|
||||||
|
vaultFile = VaultRepository.readVaultFile(this);
|
||||||
|
} catch (VaultRepositoryException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Dialogs.showErrorDialog(this, R.string.vault_load_error, e, (dialog, which) -> {
|
||||||
|
finish();
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!vaultFile.isEncrypted()) {
|
||||||
|
try {
|
||||||
|
_vaultManager.loadFrom(vaultFile);
|
||||||
|
} catch (VaultRepositoryException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Dialogs.showErrorDialog(this, R.string.vault_load_error, e, (dialog, which) -> {
|
||||||
|
finish();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!_vaultManager.isVaultLoaded()) {
|
if (!_vaultManager.isVaultLoaded()) {
|
||||||
startAuthActivity(false);
|
startAuthActivity(false);
|
||||||
} else if (_loaded) {
|
} else if (_loaded) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ import com.beemdevelopment.aegis.services.NotificationService;
|
||||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -30,8 +29,6 @@ public class VaultManager {
|
||||||
private final Context _context;
|
private final Context _context;
|
||||||
private final Preferences _prefs;
|
private final Preferences _prefs;
|
||||||
|
|
||||||
private VaultFile _vaultFile;
|
|
||||||
private VaultRepositoryException _vaultFileError;
|
|
||||||
private VaultRepository _repo;
|
private VaultRepository _repo;
|
||||||
|
|
||||||
private final VaultBackupManager _backups;
|
private final VaultBackupManager _backups;
|
||||||
|
@ -46,35 +43,11 @@ public class VaultManager {
|
||||||
_backups = new VaultBackupManager(_context);
|
_backups = new VaultBackupManager(_context);
|
||||||
_androidBackups = new BackupManager(context);
|
_androidBackups = new BackupManager(context);
|
||||||
_lockListeners = new ArrayList<>();
|
_lockListeners = new ArrayList<>();
|
||||||
loadVaultFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadVaultFile() {
|
|
||||||
try {
|
|
||||||
_vaultFile = VaultRepository.readVaultFile(_context);
|
|
||||||
} catch (VaultRepositoryException e) {
|
|
||||||
if (!(e.getCause() instanceof FileNotFoundException)) {
|
|
||||||
_vaultFileError = e;
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_vaultFile != null && !_vaultFile.isEncrypted()) {
|
|
||||||
try {
|
|
||||||
loadFrom(_vaultFile, null);
|
|
||||||
} catch (VaultRepositoryException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
_vaultFile = null;
|
|
||||||
_vaultFileError = e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the vault repository with a new empty vault and the given creds. It can
|
* Initializes the vault repository with a new empty vault and the given creds. It can
|
||||||
* only be called if isVaultLoaded() returns false.
|
* only be called if isVaultLoaded() returns false.
|
||||||
*
|
|
||||||
* Calling this method removes the manager's internal reference to the raw vault file (if it had one).
|
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public VaultRepository initNew(@Nullable VaultFileCredentials creds) throws VaultRepositoryException {
|
public VaultRepository initNew(@Nullable VaultFileCredentials creds) throws VaultRepositoryException {
|
||||||
|
@ -82,8 +55,6 @@ public class VaultManager {
|
||||||
throw new IllegalStateException("Vault manager is already initialized");
|
throw new IllegalStateException("Vault manager is already initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
_vaultFile = null;
|
|
||||||
_vaultFileError = null;
|
|
||||||
_repo = new VaultRepository(_context, new Vault(), creds);
|
_repo = new VaultRepository(_context, new Vault(), creds);
|
||||||
save();
|
save();
|
||||||
|
|
||||||
|
@ -97,8 +68,6 @@ public class VaultManager {
|
||||||
/**
|
/**
|
||||||
* Initializes the vault repository by decrypting the given vaultFile with the given
|
* Initializes the vault repository by decrypting the given vaultFile with the given
|
||||||
* creds. It can only be called if isVaultLoaded() returns false.
|
* creds. It can only be called if isVaultLoaded() returns false.
|
||||||
*
|
|
||||||
* Calling this method removes the manager's internal reference to the raw vault file (if it had one).
|
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public VaultRepository loadFrom(@NonNull VaultFile vaultFile, @Nullable VaultFileCredentials creds) throws VaultRepositoryException {
|
public VaultRepository loadFrom(@NonNull VaultFile vaultFile, @Nullable VaultFileCredentials creds) throws VaultRepositoryException {
|
||||||
|
@ -106,8 +75,6 @@ public class VaultManager {
|
||||||
throw new IllegalStateException("Vault manager is already initialized");
|
throw new IllegalStateException("Vault manager is already initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
_vaultFile = null;
|
|
||||||
_vaultFileError = null;
|
|
||||||
_repo = VaultRepository.fromFile(_context, vaultFile, creds);
|
_repo = VaultRepository.fromFile(_context, vaultFile, creds);
|
||||||
|
|
||||||
if (getVault().isEncryptionEnabled()) {
|
if (getVault().isEncryptionEnabled()) {
|
||||||
|
@ -117,32 +84,9 @@ public class VaultManager {
|
||||||
return getVault();
|
return getVault();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the vault repository by loading and decrypting the vault file stored in
|
|
||||||
* internal storage, with the given creds. It can only be called if isVaultLoaded()
|
|
||||||
* returns false.
|
|
||||||
*
|
|
||||||
* Calling this method removes the manager's internal reference to the raw vault file (if it had one).
|
|
||||||
*/
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public VaultRepository load(@Nullable VaultFileCredentials creds) throws VaultRepositoryException {
|
public VaultRepository loadFrom(@NonNull VaultFile vaultFile) throws VaultRepositoryException {
|
||||||
if (isVaultLoaded()) {
|
return loadFrom(vaultFile, null);
|
||||||
throw new IllegalStateException("Vault manager is already initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
loadVaultFile();
|
|
||||||
if (isVaultLoaded()) {
|
|
||||||
return _repo;
|
|
||||||
}
|
|
||||||
|
|
||||||
return loadFrom(getVaultFile(), creds);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public VaultRepository unlock(@NonNull VaultFileCredentials creds) throws VaultRepositoryException {
|
|
||||||
VaultRepository repo = loadFrom(getVaultFile(), creds);
|
|
||||||
startNotificationService();
|
|
||||||
return repo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,7 +101,6 @@ public class VaultManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
stopNotificationService();
|
stopNotificationService();
|
||||||
loadVaultFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableEncryption(VaultFileCredentials creds) throws VaultRepositoryException {
|
public void enableEncryption(VaultFileCredentials creds) throws VaultRepositoryException {
|
||||||
|
@ -270,12 +213,8 @@ public class VaultManager {
|
||||||
return _repo != null;
|
return _repo != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVaultFileLoaded() {
|
|
||||||
return _vaultFile != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVaultInitNeeded() {
|
public boolean isVaultInitNeeded() {
|
||||||
return !isVaultLoaded() && !isVaultFileLoaded() && getVaultFileError() == null;
|
return !isVaultLoaded() && !VaultRepository.fileExists(_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -287,20 +226,6 @@ public class VaultManager {
|
||||||
return _repo;
|
return _repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public VaultFile getVaultFile() {
|
|
||||||
if (_vaultFile == null) {
|
|
||||||
throw new IllegalStateException("Vault file is not in memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
return _vaultFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public VaultRepositoryException getVaultFileError() {
|
|
||||||
return _vaultFileError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts an external activity, temporarily blocks automatic lock of Aegis and
|
* Starts an external activity, temporarily blocks automatic lock of Aegis and
|
||||||
* shows an error dialog if the target activity is not found.
|
* shows an error dialog if the target activity is not found.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue