Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refer to groups by UUID #1078

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 10 additions & 8 deletions app/src/main/java/com/beemdevelopment/aegis/Preferences.java
Expand Up @@ -20,9 +20,11 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

public class Preferences {
Expand Down Expand Up @@ -478,26 +480,26 @@ public boolean isMinimizeOnCopyEnabled() {
return _prefs.getBoolean("pref_minimize_on_copy", false);
}

public void setGroupFilter(List<String> groupFilter) {
public void setGroupFilter(Set<UUID> groupFilter) {
JSONArray json = new JSONArray(groupFilter);
_prefs.edit().putString("pref_group_filter", json.toString()).apply();
_prefs.edit().putString("pref_group_filter_uuids", json.toString()).apply();
}

public List<String> getGroupFilter() {
String raw = _prefs.getString("pref_group_filter", null);
public Set<UUID> getGroupFilter() {
String raw = _prefs.getString("pref_group_filter_uuids", null);
if (raw == null || raw.isEmpty()) {
return Collections.emptyList();
return Collections.emptySet();
}

try {
JSONArray json = new JSONArray(raw);
List<String> filter = new ArrayList<>();
Set<UUID> filter = new HashSet<>();
for (int i = 0; i < json.length(); i++) {
filter.add(json.isNull(i) ? null : json.optString(i));
filter.add(json.isNull(i) ? null : UUID.fromString(json.getString(i)));
}
return filter;
} catch (JSONException e) {
return Collections.emptyList();
return Collections.emptySet();
}
}

Expand Down
Expand Up @@ -16,6 +16,7 @@
import com.beemdevelopment.aegis.vault.VaultFile;
import com.beemdevelopment.aegis.vault.VaultFileCredentials;
import com.beemdevelopment.aegis.vault.VaultFileException;
import com.beemdevelopment.aegis.vault.VaultGroup;
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
import com.beemdevelopment.aegis.vault.slots.SlotList;
import com.topjohnwu.superuser.io.SuFile;
Expand All @@ -27,6 +28,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

public class AegisImporter extends DatabaseImporter {

Expand Down Expand Up @@ -132,11 +134,31 @@ public Result convert() throws DatabaseImporterException {
Result result = new Result();

try {
JSONArray array = _obj.getJSONArray("entries");
for (int i = 0; i < array.length(); i++) {
JSONObject entryObj = array.getJSONObject(i);
if (_obj.has("groups")) {
alexbakker marked this conversation as resolved.
Show resolved Hide resolved
JSONArray groupArray = _obj.getJSONArray("groups");
for (int i = 0; i < groupArray.length(); i++) {
JSONObject groupObj = groupArray.getJSONObject(i);
try {
VaultGroup group = convertGroup(groupObj);
if (!result.getGroups().has(group)) {
result.addGroup(group);
}
} catch (DatabaseImporterEntryException e) {
result.addError(e);
}
}
}

JSONArray entryArray = _obj.getJSONArray("entries");
for (int i = 0; i < entryArray.length(); i++) {
JSONObject entryObj = entryArray.getJSONObject(i);
try {
VaultEntry entry = convertEntry(entryObj);
for (UUID groupUuid : entry.getGroups()) {
if (!result.getGroups().has(groupUuid)) {
entry.getGroups().remove(groupUuid);
}
}
result.addEntry(entry);
} catch (DatabaseImporterEntryException e) {
result.addError(e);
Expand All @@ -156,5 +178,13 @@ private static VaultEntry convertEntry(JSONObject obj) throws DatabaseImporterEn
throw new DatabaseImporterEntryException(e, obj.toString());
}
}

private static VaultGroup convertGroup(JSONObject obj) throws DatabaseImporterEntryException {
try {
return VaultGroup.fromJson(obj);
} catch (VaultEntryException e) {
throw new DatabaseImporterEntryException(e, obj.toString());
}
}
}
}
Expand Up @@ -8,6 +8,7 @@
import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.util.UUIDMap;
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.beemdevelopment.aegis.vault.VaultGroup;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.io.SuFile;
import com.topjohnwu.superuser.io.SuFileInputStream;
Expand Down Expand Up @@ -168,12 +169,17 @@ public Result convert() throws DatabaseImporterException {

public static class Result {
private UUIDMap<VaultEntry> _entries = new UUIDMap<>();
private UUIDMap<VaultGroup> _groups = new UUIDMap<>();
private List<DatabaseImporterEntryException> _errors = new ArrayList<>();

public void addEntry(VaultEntry entry) {
_entries.add(entry);
}

public void addGroup(VaultGroup group) {
_groups.add(group);
}

public void addError(DatabaseImporterEntryException error) {
_errors.add(error);
}
Expand All @@ -182,6 +188,10 @@ public UUIDMap<VaultEntry> getEntries() {
return _entries;
}

public UUIDMap<VaultGroup> getGroups() {
return _groups;
}

public List<DatabaseImporterEntryException> getErrors() {
return _errors;
}
Expand Down
@@ -1,7 +1,7 @@
package com.beemdevelopment.aegis.ui;

import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
Expand All @@ -15,7 +15,6 @@
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.AdapterView;
import android.widget.AutoCompleteTextView;
import android.widget.ImageView;
import android.widget.LinearLayout;
Expand Down Expand Up @@ -54,11 +53,13 @@
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
import com.beemdevelopment.aegis.ui.dialogs.IconPickerDialog;
import com.beemdevelopment.aegis.ui.glide.IconLoader;
import com.beemdevelopment.aegis.ui.models.VaultGroupModel;
import com.beemdevelopment.aegis.ui.tasks.ImportFileTask;
import com.beemdevelopment.aegis.ui.views.IconAdapter;
import com.beemdevelopment.aegis.util.Cloner;
import com.beemdevelopment.aegis.util.IOUtils;
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.beemdevelopment.aegis.vault.VaultGroup;
import com.beemdevelopment.aegis.vault.VaultRepository;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
Expand All @@ -73,11 +74,14 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.TreeSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
Expand All @@ -90,7 +94,7 @@ public class EditEntryActivity extends AegisActivity {
private boolean _isNew = false;
private boolean _isManual = false;
private VaultEntry _origEntry;
private TreeSet<String> _groups;
private Collection<VaultGroup> _groups;
private boolean _hasCustomIcon = false;
// keep track of icon changes separately as the generated jpeg's are not deterministic
private boolean _hasChangedIcon = false;
Expand All @@ -114,7 +118,7 @@ public class EditEntryActivity extends AegisActivity {
private AutoCompleteTextView _dropdownAlgo;
private TextInputLayout _dropdownAlgoLayout;
private AutoCompleteTextView _dropdownGroup;
private List<String> _dropdownGroupList = new ArrayList<>();
private List<VaultGroupModel> _dropdownGroupList = new ArrayList<>();

private KropView _kropView;

Expand Down Expand Up @@ -262,8 +266,13 @@ protected void onCreate(Bundle savedInstanceState) {
updateAdvancedFieldStatus(_origEntry.getInfo().getTypeId());
updatePinFieldVisibility(_origEntry.getInfo().getTypeId());

String group = _origEntry.getGroup();
setGroup(group);
Set<UUID> groups = _origEntry.getGroups();
if (groups.isEmpty()) {
setGroup(new VaultGroupModel(getString(R.string.no_group)));
} else {
VaultGroup group = _vaultManager.getVault().getGroupByUUID(groups.iterator().next());
setGroup(new VaultGroupModel(group));
}

// Update the icon if the issuer or name has changed
_textIssuer.addTextChangedListener(_nameChangeListener);
Expand Down Expand Up @@ -327,24 +336,31 @@ protected void onCreate(Bundle savedInstanceState) {
startIconSelection();
});

_dropdownGroup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
private int prevPosition = _dropdownGroupList.indexOf(_dropdownGroup.getText().toString());

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == _dropdownGroupList.size() - 1) {
Dialogs.showTextInputDialog(EditEntryActivity.this, R.string.set_group, R.string.group_name_hint, text -> {
String groupName = new String(text);
if (!groupName.isEmpty()) {
_groups.add(groupName);
updateGroupDropdownList();
_dropdownGroup.setText(groupName, false);
_dropdownGroup.setOnItemClickListener((parent, view, position, id) -> {
VaultGroupModel selectedGroup = _dropdownGroupList.get(position);
if (selectedGroup.isPlaceholder() && Objects.equals(selectedGroup.getName(), getString(R.string.new_group))) {
Dialogs.TextInputListener onAddGroup = text -> {
String groupName = new String(text).trim();
if (!groupName.isEmpty()) {
VaultGroup group = _vaultManager.getVault().findGroupByName(groupName);
if (group == null) {
group = new VaultGroup(groupName);
_vaultManager.getVault().addGroup(group);
}
});
_dropdownGroup.setText(_dropdownGroupList.get(prevPosition), false);
} else {
prevPosition = position;
}

updateGroupDropdownList();
setGroup(new VaultGroupModel(group));
}
};

DialogInterface.OnCancelListener onCancel = dialogInterface -> {
VaultGroupModel previous = (VaultGroupModel) _dropdownGroup.getTag();
_dropdownGroup.setText(previous.getName(), false);
};

Dialogs.showTextInputDialog(EditEntryActivity.this, R.string.set_group, R.string.group_name_hint, onAddGroup, onCancel);
} else {
setGroup(_dropdownGroupList.get(position));
}
});

Expand All @@ -365,13 +381,9 @@ private void updatePinFieldVisibility(String otpType) {
_textPin.setHint(otpType.equals(MotpInfo.ID) ? R.string.motp_pin : R.string.yandex_pin);
}

private void setGroup(String groupName) {
int pos = 0;
if (groupName != null) {
pos = _groups.contains(groupName) ? _groups.headSet(groupName).size() + 1 : 0;
}

_dropdownGroup.setText(_dropdownGroupList.get(pos), false);
private void setGroup(VaultGroupModel group) {
_dropdownGroup.setText(group.getName(), false);
_dropdownGroup.setTag(group);
}

private void openAdvancedSettings() {
Expand All @@ -395,11 +407,10 @@ private void openAdvancedSettings() {
}

private void updateGroupDropdownList() {
Resources res = getResources();
_dropdownGroupList.clear();
_dropdownGroupList.add(res.getString(R.string.no_group));
_dropdownGroupList.addAll(_groups);
_dropdownGroupList.add(res.getString(R.string.new_group));
_dropdownGroupList.add(new VaultGroupModel(getString(R.string.new_group)));
_dropdownGroupList.addAll(_groups.stream().map(VaultGroupModel::new).collect(Collectors.toList()));
_dropdownGroupList.add(new VaultGroupModel(getString(R.string.no_group)));
}

private boolean hasUnsavedChanges(VaultEntry newEntry) {
Expand Down Expand Up @@ -726,12 +737,13 @@ private VaultEntry parseEntry() throws ParseException {
entry.setName(_textName.getText().toString());
entry.setNote(_textNote.getText().toString());

int groupPos = _dropdownGroupList.indexOf(_dropdownGroup.getText().toString());
if (groupPos != 0) {
String group = _dropdownGroupList.get(groupPos);
entry.setGroup(group);
VaultGroupModel group = (VaultGroupModel) _dropdownGroup.getTag();
if (group.isPlaceholder()) {
entry.setGroups(new HashSet<>());
} else {
entry.setGroup(null);
Set<UUID> groups = new HashSet<>();
groups.add(group.getUUID());
entry.setGroups(groups);
}

if (_hasChangedIcon) {
Expand Down