2019-02-07 22:39:33 +01:00
|
|
|
package com.beemdevelopment.aegis.db;
|
|
|
|
|
|
|
|
import com.beemdevelopment.aegis.encoding.Base64;
|
|
|
|
import com.beemdevelopment.aegis.encoding.Base64Exception;
|
|
|
|
import com.beemdevelopment.aegis.otp.GoogleAuthInfo;
|
|
|
|
import com.beemdevelopment.aegis.otp.OtpInfo;
|
|
|
|
import com.beemdevelopment.aegis.otp.OtpInfoException;
|
2019-09-04 21:42:01 +02:00
|
|
|
import com.beemdevelopment.aegis.otp.TotpInfo;
|
Introduce UUIDMap for storing objects that are keyed by a UUID
This patch introduces the new ``UUIDMap`` type, reducing code duplication and
making UUID lookups faster. We currently already use UUIDs as the identifier for
the ``DatabaseEntry`` and ``Slot`` types, but the way lookups by UUID work are
kind of ugly, as we simply iterate over the list until we find a match. As we're
probably going to have more types like this soon (groups and icons, for
example), I figured it'd be good to abstract this away into a separate type and
make it a map instead of a list.
The only thing that has gotten slower is the ``swap`` method. The internal
``LinkedHashMap`` retains insertion order with a linked list, but does not know
about the position of the values, so we basically have to copy the entire map to
simply swap two values. I don't think it's too big of a deal, because swap
operations still take less than a millisecond even with large vaults, but
suggestions for improving this are welcome.
I had to update gradle and JUnit to be able to use the new ``assertThrows``
assertion method, so this patch includes that as well.
2019-06-10 18:25:44 +02:00
|
|
|
import com.beemdevelopment.aegis.util.UUIDMap;
|
2016-11-13 18:21:00 +01:00
|
|
|
|
2017-12-03 18:06:35 +01:00
|
|
|
import org.json.JSONException;
|
2016-11-13 18:21:00 +01:00
|
|
|
import org.json.JSONObject;
|
|
|
|
|
2018-09-25 19:36:56 +02:00
|
|
|
import java.util.Arrays;
|
2018-12-11 11:44:36 +01:00
|
|
|
import java.util.Objects;
|
2018-03-13 18:30:47 +01:00
|
|
|
import java.util.UUID;
|
2016-11-13 18:21:00 +01:00
|
|
|
|
Introduce UUIDMap for storing objects that are keyed by a UUID
This patch introduces the new ``UUIDMap`` type, reducing code duplication and
making UUID lookups faster. We currently already use UUIDs as the identifier for
the ``DatabaseEntry`` and ``Slot`` types, but the way lookups by UUID work are
kind of ugly, as we simply iterate over the list until we find a match. As we're
probably going to have more types like this soon (groups and icons, for
example), I figured it'd be good to abstract this away into a separate type and
make it a map instead of a list.
The only thing that has gotten slower is the ``swap`` method. The internal
``LinkedHashMap`` retains insertion order with a linked list, but does not know
about the position of the values, so we basically have to copy the entire map to
simply swap two values. I don't think it's too big of a deal, because swap
operations still take less than a millisecond even with large vaults, but
suggestions for improving this are welcome.
I had to update gradle and JUnit to be able to use the new ``assertThrows``
assertion method, so this patch includes that as well.
2019-06-10 18:25:44 +02:00
|
|
|
public class DatabaseEntry extends UUIDMap.Value {
|
2017-12-27 21:01:53 +01:00
|
|
|
private String _name = "";
|
2018-06-06 16:15:31 +02:00
|
|
|
private String _issuer = "";
|
2018-12-11 11:44:36 +01:00
|
|
|
private String _group;
|
2018-06-06 16:15:31 +02:00
|
|
|
private OtpInfo _info;
|
2018-06-07 12:27:42 +02:00
|
|
|
private byte[] _icon;
|
2017-08-26 21:15:53 +02:00
|
|
|
|
2018-10-06 22:23:38 +02:00
|
|
|
private DatabaseEntry(UUID uuid, OtpInfo info) {
|
Introduce UUIDMap for storing objects that are keyed by a UUID
This patch introduces the new ``UUIDMap`` type, reducing code duplication and
making UUID lookups faster. We currently already use UUIDs as the identifier for
the ``DatabaseEntry`` and ``Slot`` types, but the way lookups by UUID work are
kind of ugly, as we simply iterate over the list until we find a match. As we're
probably going to have more types like this soon (groups and icons, for
example), I figured it'd be good to abstract this away into a separate type and
make it a map instead of a list.
The only thing that has gotten slower is the ``swap`` method. The internal
``LinkedHashMap`` retains insertion order with a linked list, but does not know
about the position of the values, so we basically have to copy the entire map to
simply swap two values. I don't think it's too big of a deal, because swap
operations still take less than a millisecond even with large vaults, but
suggestions for improving this are welcome.
I had to update gradle and JUnit to be able to use the new ``assertThrows``
assertion method, so this patch includes that as well.
2019-06-10 18:25:44 +02:00
|
|
|
super(uuid);
|
2017-08-26 21:15:53 +02:00
|
|
|
_info = info;
|
2018-10-06 22:23:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public DatabaseEntry(OtpInfo info) {
|
Introduce UUIDMap for storing objects that are keyed by a UUID
This patch introduces the new ``UUIDMap`` type, reducing code duplication and
making UUID lookups faster. We currently already use UUIDs as the identifier for
the ``DatabaseEntry`` and ``Slot`` types, but the way lookups by UUID work are
kind of ugly, as we simply iterate over the list until we find a match. As we're
probably going to have more types like this soon (groups and icons, for
example), I figured it'd be good to abstract this away into a separate type and
make it a map instead of a list.
The only thing that has gotten slower is the ``swap`` method. The internal
``LinkedHashMap`` retains insertion order with a linked list, but does not know
about the position of the values, so we basically have to copy the entire map to
simply swap two values. I don't think it's too big of a deal, because swap
operations still take less than a millisecond even with large vaults, but
suggestions for improving this are welcome.
I had to update gradle and JUnit to be able to use the new ``assertThrows``
assertion method, so this patch includes that as well.
2019-06-10 18:25:44 +02:00
|
|
|
super();
|
|
|
|
_info = info;
|
2017-08-26 21:15:53 +02:00
|
|
|
}
|
|
|
|
|
2018-06-06 16:15:31 +02:00
|
|
|
public DatabaseEntry(OtpInfo info, String name, String issuer) {
|
|
|
|
this(info);
|
|
|
|
setName(name);
|
|
|
|
setIssuer(issuer);
|
|
|
|
}
|
|
|
|
|
2018-10-06 22:23:38 +02:00
|
|
|
public DatabaseEntry(GoogleAuthInfo info) {
|
|
|
|
this(info.getOtpInfo(), info.getAccountName(), info.getIssuer());
|
|
|
|
}
|
|
|
|
|
|
|
|
public JSONObject toJson() {
|
2016-11-13 18:21:00 +01:00
|
|
|
JSONObject obj = new JSONObject();
|
2018-06-06 16:15:31 +02:00
|
|
|
|
|
|
|
try {
|
|
|
|
obj.put("type", _info.getType());
|
Introduce UUIDMap for storing objects that are keyed by a UUID
This patch introduces the new ``UUIDMap`` type, reducing code duplication and
making UUID lookups faster. We currently already use UUIDs as the identifier for
the ``DatabaseEntry`` and ``Slot`` types, but the way lookups by UUID work are
kind of ugly, as we simply iterate over the list until we find a match. As we're
probably going to have more types like this soon (groups and icons, for
example), I figured it'd be good to abstract this away into a separate type and
make it a map instead of a list.
The only thing that has gotten slower is the ``swap`` method. The internal
``LinkedHashMap`` retains insertion order with a linked list, but does not know
about the position of the values, so we basically have to copy the entire map to
simply swap two values. I don't think it's too big of a deal, because swap
operations still take less than a millisecond even with large vaults, but
suggestions for improving this are welcome.
I had to update gradle and JUnit to be able to use the new ``assertThrows``
assertion method, so this patch includes that as well.
2019-06-10 18:25:44 +02:00
|
|
|
obj.put("uuid", getUUID().toString());
|
2018-06-06 16:15:31 +02:00
|
|
|
obj.put("name", _name);
|
|
|
|
obj.put("issuer", _issuer);
|
2018-12-11 11:44:36 +01:00
|
|
|
obj.put("group", _group);
|
2018-06-07 12:27:42 +02:00
|
|
|
obj.put("icon", _icon == null ? JSONObject.NULL : Base64.encode(_icon));
|
2018-06-07 14:33:33 +02:00
|
|
|
obj.put("info", _info.toJson());
|
2018-06-06 16:15:31 +02:00
|
|
|
} catch (JSONException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
|
|
|
|
2016-11-13 18:21:00 +01:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2018-10-06 22:23:38 +02:00
|
|
|
public static DatabaseEntry fromJson(JSONObject obj) throws JSONException, OtpInfoException, Base64Exception {
|
2018-03-13 18:30:47 +01:00
|
|
|
// if there is no uuid, generate a new one
|
2018-10-06 22:23:38 +02:00
|
|
|
UUID uuid;
|
2018-03-13 18:30:47 +01:00
|
|
|
if (!obj.has("uuid")) {
|
2018-10-06 22:23:38 +02:00
|
|
|
uuid = UUID.randomUUID();
|
2018-03-13 18:30:47 +01:00
|
|
|
} else {
|
2018-10-06 22:23:38 +02:00
|
|
|
uuid = UUID.fromString(obj.getString("uuid"));
|
2018-03-13 18:30:47 +01:00
|
|
|
}
|
2018-10-06 22:23:38 +02:00
|
|
|
|
|
|
|
OtpInfo info = OtpInfo.fromJson(obj.getString("type"), obj.getJSONObject("info"));
|
|
|
|
DatabaseEntry entry = new DatabaseEntry(uuid, info);
|
|
|
|
entry.setName(obj.getString("name"));
|
|
|
|
entry.setIssuer(obj.getString("issuer"));
|
2018-12-11 11:44:36 +01:00
|
|
|
entry.setGroup(obj.optString("group", null));
|
2018-06-07 12:27:42 +02:00
|
|
|
|
2018-06-07 14:33:33 +02:00
|
|
|
Object icon = obj.get("icon");
|
|
|
|
if (icon != JSONObject.NULL) {
|
2018-10-06 22:23:38 +02:00
|
|
|
entry.setIcon(Base64.decode((String) icon));
|
2018-06-07 12:27:42 +02:00
|
|
|
}
|
2018-06-07 14:33:33 +02:00
|
|
|
|
2018-10-06 22:23:38 +02:00
|
|
|
return entry;
|
2017-08-26 21:15:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public String getName() {
|
|
|
|
return _name;
|
|
|
|
}
|
2018-06-06 16:15:31 +02:00
|
|
|
|
|
|
|
public String getIssuer() {
|
|
|
|
return _issuer;
|
|
|
|
}
|
|
|
|
|
2018-12-11 11:44:36 +01:00
|
|
|
public String getGroup() {
|
|
|
|
return _group;
|
|
|
|
}
|
|
|
|
|
2018-06-07 12:27:42 +02:00
|
|
|
public byte[] getIcon() {
|
2017-08-26 21:15:53 +02:00
|
|
|
return _icon;
|
|
|
|
}
|
2018-06-06 16:15:31 +02:00
|
|
|
|
|
|
|
public OtpInfo getInfo() {
|
2017-08-26 21:15:53 +02:00
|
|
|
return _info;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setName(String name) {
|
|
|
|
_name = name;
|
|
|
|
}
|
2018-06-06 16:15:31 +02:00
|
|
|
|
|
|
|
public void setIssuer(String issuer) {
|
|
|
|
_issuer = issuer;
|
|
|
|
}
|
|
|
|
|
2018-12-11 11:44:36 +01:00
|
|
|
public void setGroup(String group) {
|
|
|
|
_group = group;
|
|
|
|
}
|
|
|
|
|
2018-06-06 16:15:31 +02:00
|
|
|
public void setInfo(OtpInfo info) {
|
2017-08-26 21:15:53 +02:00
|
|
|
_info = info;
|
|
|
|
}
|
2018-06-07 12:27:42 +02:00
|
|
|
|
|
|
|
public void setIcon(byte[] icon) {
|
|
|
|
_icon = icon;
|
|
|
|
}
|
2018-06-07 14:33:33 +02:00
|
|
|
|
|
|
|
public boolean hasIcon() {
|
|
|
|
return _icon != null;
|
|
|
|
}
|
2018-09-25 19:36:56 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
if (!(o instanceof DatabaseEntry)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DatabaseEntry entry = (DatabaseEntry) o;
|
2019-09-04 21:42:01 +02:00
|
|
|
return super.equals(entry) && equivalates(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reports whether this entry is equivalent to the given entry. The UUIDs of these
|
|
|
|
* entries are ignored during the comparison, so they are not necessarily the same
|
|
|
|
* instance.
|
|
|
|
*/
|
|
|
|
public boolean equivalates(DatabaseEntry entry) {
|
|
|
|
return getName().equals(entry.getName())
|
2018-09-25 19:36:56 +02:00
|
|
|
&& getIssuer().equals(entry.getIssuer())
|
2018-12-11 11:44:36 +01:00
|
|
|
&& Objects.equals(getGroup(), entry.getGroup())
|
2018-09-25 19:36:56 +02:00
|
|
|
&& getInfo().equals(entry.getInfo())
|
|
|
|
&& Arrays.equals(getIcon(), entry.getIcon());
|
|
|
|
}
|
2019-09-04 21:42:01 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reports whether this entry has its values set to the defaults.
|
|
|
|
*/
|
|
|
|
public boolean isDefault() {
|
|
|
|
return equivalates(getDefault());
|
|
|
|
}
|
|
|
|
|
|
|
|
public static DatabaseEntry getDefault() {
|
|
|
|
try {
|
|
|
|
return new DatabaseEntry(new TotpInfo(null));
|
|
|
|
} catch (OtpInfoException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
|
|
|
}
|
2016-11-13 18:21:00 +01:00
|
|
|
}
|