pull/1696/merge
Ceoslugpk 2 months ago committed by GitHub
commit 3f448f5e90
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -3,17 +3,8 @@ apply plugin: 'com.google.protobuf'
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
def getCmdOutput = { cmd ->
def stdout = new ByteArrayOutputStream()
exec {
commandLine cmd
standardOutput = stdout
}
return stdout.toString().trim()
}
def getGitHash = { -> return getCmdOutput(["git", "rev-parse", "--short", "HEAD"]) }
def getGitBranch = { -> return getCmdOutput(["git", "rev-parse", "--abbrev-ref", "HEAD"]) }
def getGitHash = { -> return "unknown" }
def getGitBranch = { -> return "unknown" }
def packageName = "com.beemdevelopment.aegis"
def fileProviderAuthority = "${packageName}.fileprovider"
@ -26,7 +17,7 @@ android {
defaultConfig {
applicationId "${packageName}"
minSdkVersion 23
minSdkVersion 16
targetSdkVersion 35
versionCode 80
versionName "3.4.1"
@ -98,7 +89,7 @@ android {
cruncherEnabled = false
}
defaultConfig {
vectorDrawables.generatedDensities = []
vectorDrawables.useSupportLibrary = true
}
packagingOptions {
@ -112,8 +103,8 @@ android {
}
compileOptions {
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
coreLibraryDesugaringEnabled true
}
lint {
@ -191,7 +182,7 @@ dependencies {
implementation "com.github.topjohnwu.libsu:core:${libsuVersion}"
implementation "com.github.topjohnwu.libsu:io:${libsuVersion}"
implementation "com.google.guava:guava:${guavaVersion}-android"
implementation 'com.google.android.material:material:1.12.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'com.google.protobuf:protobuf-javalite:4.31.0'
implementation 'com.google.zxing:core:3.5.3'
implementation('com.mikepenz:aboutlibraries:11.2.3') {

@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-sdk tools:overrideLibrary="androidx.camera.video, androidx.camera.camera2, androidx.camera.lifecycle, androidx.camera.view, androidx.camera.core, com.mikepenz.aboutlibraries" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.VIBRATE" />
@ -20,17 +22,13 @@
<application
android:name=".AegisApplication"
android:allowBackup="true"
android:fullBackupOnly="true"
android:fullBackupContent="@xml/backup_rules_old"
android:dataExtractionRules="@xml/backup_rules"
android:backupAgent=".AegisBackupAgent"
android:enableOnBackInvokedCallback="true"
android:icon="@mipmap/${iconName}"
android:label="Aegis"
android:supportsRtl="true"
android:largeHeap="true"
android:theme="@style/Theme.Aegis.Launch"
tools:targetApi="tiramisu">
android:theme="@style/Theme.Aegis.Launch">
<activity android:name=".ui.TransferEntriesActivity"
android:label="@string/title_activity_transfer" />
<activity
@ -109,7 +107,8 @@
android:label="@string/tile_open_vault"
android:icon="@drawable/ic_aegis_quicksettings"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
android:exported="true"
tools:targetApi="n">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
@ -122,7 +121,8 @@
android:label="@string/tile_open_scanner"
android:icon="@drawable/ic_aegis_quicksettings"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
android:exported="true"
tools:targetApi="n">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>

@ -28,13 +28,17 @@ public class BiometricSlotInitializer extends BiometricPrompt.AuthenticationCall
public BiometricSlotInitializer(Fragment fragment, Listener listener) {
_listener = listener;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
_prompt = new BiometricPrompt(fragment, new UiThreadExecutor(), this);
}
}
public BiometricSlotInitializer(FragmentActivity activity, Listener listener) {
_listener = listener;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
_prompt = new BiometricPrompt(activity, new UiThreadExecutor(), this);
}
}
/**
* Generates a new key in the Android KeyStore for the new BiometricSlot,
@ -43,6 +47,11 @@ public class BiometricSlotInitializer extends BiometricPrompt.AuthenticationCall
* initialized and delivered back through the listener.
*/
public void authenticate(BiometricPrompt.PromptInfo info) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
fail(0, "Biometric authentication is not supported on this device.");
return;
}
if (_slot != null) {
throw new IllegalStateException("Biometric authentication already in progress");
}
@ -114,20 +123,26 @@ public class BiometricSlotInitializer extends BiometricPrompt.AuthenticationCall
@Override
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
super.onAuthenticationError(errorCode, errString);
fail(errorCode, errString.toString());
}
}
@Override
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
super.onAuthenticationSucceeded(result);
_listener.onInitializeSlot(_slot, Objects.requireNonNull(result.getCryptoObject()).getCipher());
}
}
@Override
public void onAuthenticationFailed() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
super.onAuthenticationFailed();
}
}
public interface Listener {
void onInitializeSlot(BiometricSlot slot, Cipher cipher);

@ -11,10 +11,20 @@ public class BiometricsHelper {
}
public static BiometricManager getManager(Context context) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
return null;
}
BiometricManager manager = BiometricManager.from(context);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
if (manager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS) {
return manager;
}
} else {
if (manager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {
return manager;
}
}
return null;
}

@ -37,6 +37,13 @@ public class AboutActivity extends AegisActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (android.os.Build.VERSION.SDK_INT < 21) {
Toast.makeText(this, "About screen is not supported on this device.", Toast.LENGTH_LONG).show();
finish();
return;
}
if (abortIfOrphan(savedInstanceState)) {
return;
}

@ -129,6 +129,7 @@ public class AuthActivity extends AegisActivity {
// 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 (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (_slots.has(BiometricSlot.class) && BiometricsHelper.isAvailable(this)) {
boolean invalidated = false;
@ -163,6 +164,7 @@ public class AuthActivity extends AegisActivity {
biometricsButton.setVisibility(View.GONE);
}
}
}
_decryptButton.setOnClickListener(v -> {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
@ -177,12 +179,13 @@ public class AuthActivity extends AegisActivity {
_decryptButton.setEnabled(false);
});
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
biometricsButton.setOnClickListener(v -> {
if (_prefs.isPasswordReminderNeeded()) {
Dialogs.showSecureDialog(new MaterialAlertDialogBuilder(this, R.style.ThemeOverlay_Aegis_AlertDialog_Warning)
.setTitle(getString(R.string.password_reminder_dialog_title))
.setMessage(getString(R.string.password_reminder_dialog_message))
.setCancelable(false)
.setCancelable(false))
.setIconAttribute(android.R.attr.alertDialogIcon)
.setPositiveButton(android.R.string.ok, (dialog1, which) -> {
showBiometricPrompt();
@ -193,6 +196,7 @@ public class AuthActivity extends AegisActivity {
}
});
}
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
@ -216,29 +220,35 @@ public class AuthActivity extends AegisActivity {
focusPasswordField();
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (_bioKey != null && _bioPrompt == null && !_inhibitBioPrompt && !remindPassword) {
_bioPrompt = showBiometricPrompt();
}
}
_inhibitBioPrompt = false;
}
@Override
public void onPause() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (!isChangingConfigurations() && _bioPrompt != null) {
_bioPrompt.cancelAuthentication();
_bioPrompt = null;
}
}
super.onPause();
}
@Override
public void onAttachedToWindow() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (_bioKey != null && _prefs.isPasswordReminderNeeded()) {
showPasswordReminder();
}
}
}
private void focusPasswordField() {
_textPassword.requestFocus();
@ -268,7 +278,8 @@ public class AuthActivity extends AegisActivity {
}
public BiometricPrompt showBiometricPrompt() {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(_textPassword.getWindowToken(), 0);
Cipher cipher;
@ -291,6 +302,8 @@ public class AuthActivity extends AegisActivity {
prompt.authenticate(info, cryptoObj);
return prompt;
}
return null;
}
private void finish(MasterKey key, boolean isSlotRepaired) {
VaultFileCredentials creds = new VaultFileCredentials(key, _slots);
@ -366,6 +379,7 @@ public class AuthActivity extends AegisActivity {
private class BiometricPromptListener extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
super.onAuthenticationError(errorCode, errString);
_bioPrompt = null;
@ -374,9 +388,11 @@ public class AuthActivity extends AegisActivity {
Toast.makeText(AuthActivity.this, errString, Toast.LENGTH_LONG).show();
}
}
}
@Override
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
super.onAuthenticationSucceeded(result);
_bioPrompt = null;
@ -393,10 +409,13 @@ public class AuthActivity extends AegisActivity {
finish(key, false);
}
}
@Override
public void onAuthenticationFailed() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
super.onAuthenticationFailed();
}
}
}
}

@ -240,10 +240,15 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
dialog.dismiss();
startScanImageActivity();
});
view.findViewById(R.id.fab_scan).setOnClickListener(v3 -> {
View fabScan = view.findViewById(R.id.fab_scan);
if (android.os.Build.VERSION.SDK_INT < 21) {
fabScan.setVisibility(View.GONE);
} else {
fabScan.setOnClickListener(v3 -> {
dialog.dismiss();
startScanActivity();
});
}
Dialogs.showSecureDialog(dialog);
});
@ -805,7 +810,9 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
switch (action) {
case "scan":
if (android.os.Build.VERSION.SDK_INT >= 21) {
startScanActivity();
}
break;
}
@ -974,6 +981,10 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
_menu = menu;
getMenuInflater().inflate(R.menu.menu_main, menu);
if (android.os.Build.VERSION.SDK_INT < 21) {
menu.findItem(R.id.action_about).setVisible(false);
}
updateLockIcon();
updateSortCategoryMenu();
@ -1050,8 +1061,10 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
if (itemId == R.id.action_settings) {
startPreferencesActivity();
} else if (itemId == R.id.action_about) {
if (android.os.Build.VERSION.SDK_INT >= 21) {
Intent intent = new Intent(this, AboutActivity.class);
startActivity(intent);
}
} else if (itemId == R.id.action_lock) {
_vaultManager.lock(true);
} else {

@ -33,6 +33,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@androidx.annotation.RequiresApi(21)
public class ScannerActivity extends AegisActivity implements QrCodeAnalyzer.Listener {
private ProcessCameraProvider _cameraProvider;
private ListenableFuture<ProcessCameraProvider> _cameraProviderFuture;
@ -52,6 +53,13 @@ public class ScannerActivity extends AegisActivity implements QrCodeAnalyzer.Lis
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (android.os.Build.VERSION.SDK_INT < 21) {
Toast.makeText(this, R.string.camera_not_supported, Toast.LENGTH_LONG).show();
finish();
return;
}
if (abortIfOrphan(savedInstanceState)) {
return;
}

@ -109,6 +109,7 @@ public class SecurityPreferencesFragment extends PreferencesFragment {
_biometricsPreference = requirePreference("pref_biometrics");
_biometricsPreference.setOnPreferenceChangeListener((preference, newValue) -> {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
VaultFileCredentials creds = _vaultManager.getVault().getCredentials();
SlotList slots = creds.getSlots();
@ -138,6 +139,7 @@ public class SecurityPreferencesFragment extends PreferencesFragment {
saveAndBackupVault();
updateEncryptionPreferences();
}
}
return false;
});
@ -271,12 +273,20 @@ public class SecurityPreferencesFragment extends PreferencesFragment {
SlotList slots = _vaultManager.getVault().getCredentials().getSlots();
boolean multiBackupPassword = slots.findBackupPasswordSlots().size() > 1;
boolean multiPassword = slots.findRegularPasswordSlots().size() > 1;
_setPasswordPreference.setEnabled(!multiPassword);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
boolean multiBio = slots.findAll(BiometricSlot.class).size() > 1;
boolean canUseBio = BiometricsHelper.isAvailable(requireContext());
_setPasswordPreference.setEnabled(!multiPassword);
_biometricsPreference.setEnabled(canUseBio && !multiBio);
_biometricsPreference.setChecked(slots.has(BiometricSlot.class), true);
_passwordReminderPreference.setVisible(slots.has(BiometricSlot.class));
} else {
_biometricsPreference.setEnabled(false);
_biometricsPreference.setChecked(false, true);
_passwordReminderPreference.setVisible(false);
}
_backupPasswordChangePreference.setEnabled(!multiBackupPassword);
} else {
_setPasswordPreference.setEnabled(false);
@ -399,6 +409,7 @@ public class SecurityPreferencesFragment extends PreferencesFragment {
private class RegisterBiometricsListener implements BiometricSlotInitializer.Listener {
@Override
public void onInitializeSlot(BiometricSlot slot, Cipher cipher) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
VaultFileCredentials creds = _vaultManager.getVault().getCredentials();
try {
slot.setKey(creds.getKey(), cipher);
@ -413,14 +424,17 @@ public class SecurityPreferencesFragment extends PreferencesFragment {
saveAndBackupVault();
updateEncryptionPreferences();
}
}
@Override
public void onSlotInitializationFailed(int errorCode, @NonNull CharSequence errString) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (!BiometricsHelper.isCanceled(errorCode)) {
Dialogs.showErrorDialog(requireContext(), R.string.encryption_enable_biometrics_error, errString);
}
}
}
}
private class EnableEncryptionListener implements Dialogs.PasswordSlotListener {
@Override

@ -98,6 +98,7 @@ public class SecuritySetupSlide extends SlideFragment {
}
private void showBiometricPrompt() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
BiometricSlotInitializer initializer = new BiometricSlotInitializer(this, new BiometricsListener());
BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder()
.setTitle(getString(R.string.set_up_biometric))
@ -105,6 +106,7 @@ public class SecuritySetupSlide extends SlideFragment {
.build();
initializer.authenticate(info);
}
}
private void deriveKey() {
PasswordSlot slot = new PasswordSlot();
@ -119,9 +121,11 @@ public class SecuritySetupSlide extends SlideFragment {
case CRYPT_TYPE_NONE:
return true;
case CRYPT_TYPE_BIOMETRIC:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (!_creds.getSlots().has(BiometricSlot.class)) {
return false;
}
}
// intentional fallthrough
case CRYPT_TYPE_PASS:
if (EditTextHelper.areEditTextsEqual(_textPassword, _textPasswordConfirm)) {
@ -140,7 +144,7 @@ public class SecuritySetupSlide extends SlideFragment {
Toast.makeText(requireContext(), R.string.password_equality_error, Toast.LENGTH_SHORT).show();
} else if (_cryptType != SecurityPickerSlide.CRYPT_TYPE_BIOMETRIC) {
deriveKey();
} else if (!_creds.getSlots().has(BiometricSlot.class)) {
} else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M && !_creds.getSlots().has(BiometricSlot.class)) {
showBiometricPrompt();
}
}
@ -170,6 +174,7 @@ public class SecuritySetupSlide extends SlideFragment {
private class BiometricsListener implements BiometricSlotInitializer.Listener {
@Override
public void onInitializeSlot(BiometricSlot slot, Cipher cipher) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
try {
slot.setKey(_creds.getKey(), cipher);
_creds.getSlots().add(slot);
@ -181,12 +186,15 @@ public class SecuritySetupSlide extends SlideFragment {
deriveKey();
}
}
@Override
public void onSlotInitializationFailed(int errorCode, @NonNull CharSequence errString) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (!BiometricsHelper.isCanceled(errorCode)) {
Dialogs.showErrorDialog(requireContext(), R.string.encryption_enable_biometrics_error, errString);
}
}
}
}
}

@ -16,7 +16,8 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:paddingHorizontal="48dp"
android:paddingLeft="48dp"
android:paddingRight="48dp"
android:paddingTop="48dp"
android:orientation="vertical">
@ -126,6 +127,7 @@
android:textAllCaps="true"
android:textStyle="bold"
android:textColor="?attr/colorOnSurfaceDim"
android:paddingVertical="50dp" />
android:paddingTop="50dp"
android:paddingBottom="50dp" />
</LinearLayout>
</ScrollView>

@ -240,7 +240,6 @@
</LinearLayout>
<RelativeLayout
android:foreground="?android:attr/selectableItemBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/accordian_header"
@ -275,7 +274,8 @@
android:orientation="vertical"
android:visibility="gone"
android:alpha="0"
android:layout_marginHorizontal="10dp">
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<LinearLayout
android:id="@+id/layout_type_algo"
android:layout_width="match_parent"

@ -26,7 +26,7 @@
android:layout_width="15dp"
android:layout_height="match_parent"
android:layout_marginStart="-11dp"
android:backgroundTint="?attr/colorFavorite"
app:backgroundTint="?attr/colorFavorite"
android:background="@drawable/favorite_indicator" />
<RelativeLayout
@ -125,7 +125,6 @@
android:fontFamily="sans-serif-light"
tools:text="012 345"
android:id="@+id/profile_code"
android:layoutDirection="ltr"
android:textSize="34sp"
android:layout_below="@id/description"
android:textColor="?attr/colorCode"

@ -619,4 +619,5 @@
<item quantity="one">%d item selected</item>
<item quantity="other">%d items selected</item>
</plurals>
<string name="camera_not_supported">Camera is not supported on this device.</string>
</resources>

Loading…
Cancel
Save