Show dialog when trying to import from a recent Google Auth version

This commit is contained in:
Alexander Bakker 2022-06-04 14:16:30 +02:00
parent ac123918c2
commit 49b334ff70
5 changed files with 54 additions and 22 deletions

View file

@ -13,6 +13,7 @@ import com.topjohnwu.superuser.io.SuFileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
@ -59,6 +60,10 @@ public abstract class DatabaseImporter {
return new SuFile(man.getApplicationInfo(pkgName, 0).dataDir, subPath);
}
public boolean isInstalledAppVersionSupported() {
return true;
}
protected abstract State read(InputStream stream, boolean isInternal) throws DatabaseImporterException;
public State read(InputStream stream) throws DatabaseImporterException {
@ -91,7 +96,7 @@ public abstract class DatabaseImporter {
return Collections.unmodifiableList(_importers);
}
public static class Definition {
public static class Definition implements Serializable {
private final String _name;
private final Class<? extends DatabaseImporter> _type;
private final @StringRes int _help;

View file

@ -1,6 +1,7 @@
package com.beemdevelopment.aegis.importers;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
@ -32,7 +33,19 @@ public class GoogleAuthImporter extends DatabaseImporter {
protected SuFile getAppPath() throws PackageManager.NameNotFoundException {
return getAppPath(_pkgName, _subPath);
}
@Override
public boolean isInstalledAppVersionSupported() {
PackageInfo info;
try {
info = requireContext().getPackageManager().getPackageInfo(_pkgName, 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
return info.versionCode <= 5000100;
}
@Override
public State read(InputStream stream, boolean isInternal) throws DatabaseImporterException {
final Context context = requireContext();

View file

@ -83,21 +83,35 @@ public class ImportEntriesActivity extends AegisActivity {
});
_fabScrollHelper = new FabScrollHelper(fab);
Class<? extends DatabaseImporter> importerType = (Class<? extends DatabaseImporter>) getIntent().getSerializableExtra("importerType");
startImport(importerType, (File) getIntent().getSerializableExtra("file"));
DatabaseImporter.Definition importerDef = (DatabaseImporter.Definition) getIntent().getSerializableExtra("importerDef");
startImport(importerDef, (File) getIntent().getSerializableExtra("file"));
}
private void startImport(@NonNull Class<? extends DatabaseImporter> importerType, @Nullable File file) {
private void startImport(DatabaseImporter.Definition importerDef, @Nullable File file) {
DatabaseImporter importer = DatabaseImporter.create(this, importerDef.getType());
if (file == null) {
startImportApp(importerType);
if (importer.isInstalledAppVersionSupported()) {
startImportApp(importer);
} else {
Dialogs.showSecureDialog(new AlertDialog.Builder(this)
.setTitle(R.string.warning)
.setMessage(getString(R.string.app_version_error, importerDef.getName()))
.setCancelable(false)
.setPositiveButton(R.string.yes, (dialog1, which) -> {
startImportApp(importer);
})
.setNegativeButton(R.string.no, (dialog1, which) -> {
finish();
})
.create());
}
} else {
startImportFile(importerType, file);
startImportFile(importer, file);
}
}
private void startImportFile(@NonNull Class<? extends DatabaseImporter> importerType, @NonNull File file) {
private void startImportFile(@NonNull DatabaseImporter importer, @NonNull File file) {
try (InputStream stream = new FileInputStream(file)) {
DatabaseImporter importer = DatabaseImporter.create(this, importerType);
DatabaseImporter.State state = importer.read(stream);
processImporterState(state);
} catch (FileNotFoundException e) {
@ -108,9 +122,7 @@ public class ImportEntriesActivity extends AegisActivity {
}
}
private void startImportApp(@NonNull Class<? extends DatabaseImporter> importerType) {
DatabaseImporter importer = DatabaseImporter.create(this, importerType);
private void startImportApp(@NonNull DatabaseImporter importer) {
// obtain the global root shell and close it immediately after we're done
// TODO: find a way to use SuFileInputStream with Shell.newInstance()
try (Shell shell = Shell.getShell()) {

View file

@ -42,7 +42,7 @@ import javax.crypto.Cipher;
public class ImportExportPreferencesFragment extends PreferencesFragment {
// keep a reference to the type of database converter that was selected
private Class<? extends DatabaseImporter> _importerType;
private DatabaseImporter.Definition _importerDef;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@ -50,13 +50,13 @@ public class ImportExportPreferencesFragment extends PreferencesFragment {
addPreferencesFromResource(R.xml.preferences_import_export);
if (savedInstanceState != null) {
_importerType = (Class<? extends DatabaseImporter>) savedInstanceState.getSerializable("importerType");
_importerDef = (DatabaseImporter.Definition) savedInstanceState.getSerializable("importerDef");
}
Preference importPreference = requirePreference("pref_import");
importPreference.setOnPreferenceClickListener(preference -> {
Dialogs.showImportersDialog(requireContext(), false, definition -> {
_importerType = definition.getType();
_importerDef = definition;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
@ -68,7 +68,7 @@ public class ImportExportPreferencesFragment extends PreferencesFragment {
Preference importAppPreference = requirePreference("pref_import_app");
importAppPreference.setOnPreferenceClickListener(preference -> {
Dialogs.showImportersDialog(requireContext(), true, definition -> {
startImportEntriesActivity(definition.getType(), null);
startImportEntriesActivity(definition, null);
});
return true;
});
@ -83,7 +83,7 @@ public class ImportExportPreferencesFragment extends PreferencesFragment {
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("importerType", _importerType);
outState.putSerializable("importerDef", _importerDef);
}
@Override
@ -115,7 +115,7 @@ public class ImportExportPreferencesFragment extends PreferencesFragment {
ImportFileTask.Params params = new ImportFileTask.Params(uri, "import", null);
ImportFileTask task = new ImportFileTask(requireContext(), result -> {
if (result.getException() == null) {
startImportEntriesActivity(_importerType, result.getFile());
startImportEntriesActivity(_importerDef, result.getFile());
} else {
Dialogs.showErrorDialog(requireContext(), R.string.reading_file_error, result.getException());
}
@ -123,9 +123,9 @@ public class ImportExportPreferencesFragment extends PreferencesFragment {
task.execute(getLifecycle(), params);
}
private void startImportEntriesActivity(Class<? extends DatabaseImporter> importerType, File file) {
private void startImportEntriesActivity(DatabaseImporter.Definition importerDef, File file) {
Intent intent = new Intent(requireActivity(), ImportEntriesActivity.class);
intent.putExtra("importerType", importerType);
intent.putExtra("importerDef", importerDef);
intent.putExtra("file", file);
startActivityForResult(intent, CODE_IMPORT);
}

View file

@ -16,6 +16,7 @@
<string name="yandex_pin">PIN (416 digits)</string>
<string name="suggested">Suggested</string>
<string name="usage_count">Usage count</string>
<string name="warning">Warning</string>
<string name="pref_cat_appearance_app">App</string>
<string name="pref_cat_appearance_entries">Entries</string>
@ -205,6 +206,7 @@
<string name="file_not_found">Error: File not found</string>
<string name="reading_file_error">An error occurred while trying to read the file</string>
<string name="app_lookup_error">Error: App is not installed</string>
<string name="app_version_error">The version of %s that\'s installed is not supported. Attempting to import may result in an error. Would you like to continue anyway?</string>
<string name="root_error">Error: unable to obtain root access</string>
<plurals name="imported_entries_count">
<item quantity="one">Imported %d entry</item>
@ -381,14 +383,14 @@
<string name="importer_help_duo">Supply a copy of <b>/data/data/com.duosecurity.duomobile/files/duokit/accounts.json</b>, located in the internal storage directory of DUO.</string>
<string name="importer_help_freeotp">Supply a copy of <b>/data/data/org.fedorahosted.freeotp/shared_prefs/tokens.xml</b>, located in the internal storage directory of FreeOTP.</string>
<string name="importer_help_freeotp_plus">Supply a FreeOTP+ export file.</string>
<string name="importer_help_google_authenticator">Supply a copy of <b>/data/data/com.google.android.apps.authenticator2/databases/databases</b>, located in the internal storage directory of Google Authenticator.</string>
<string name="importer_help_google_authenticator"><b>Only database files from Google Authenticator v5.10 and prior are supported</b>.\n\nSupply a copy of <b>/data/data/com.google.android.apps.authenticator2/databases/databases</b>, located in the internal storage directory of Google Authenticator.</string>
<string name="importer_help_microsoft_authenticator">Supply a copy of <b>/data/data/com.azure.authenticator/databases/PhoneFactor</b>, located in the internal storage directory of Microsoft Authenticator.</string>
<string name="importer_help_plain_text">Supply a plain text file with a Google Authenticator URI on each line.</string>
<string name="importer_help_steam">Supply a copy of <b>/data/data/com.valvesoftware.android.steam.community/files/Steamguard-*.json</b>, located in the internal storage directory of Steam.</string>
<string name="importer_help_totp_authenticator">Supply a TOTP Authenticator export file.</string>
<string name="importer_help_winauth">Supply a WinAuth export file.</string>
<string name="importer_encrypted_exception_google_authenticator">"Encrypted entry was skipped: %s"</string>
<string name="importer_encrypted_exception_google_authenticator">Encrypted entry was skipped: %s</string>
<string name="importer_help_direct">Import entries directly from %s. This requires the app to be installed on this device and for root access to be granted to Aegis.</string>
<string name="groups">Groups</string>