use dedicated hash object instead of byte[] for caps
this way we can store the algo alongside the object
This commit is contained in:
parent
6458c6e9f9
commit
a2b21d97eb
|
@ -5,6 +5,7 @@ import com.google.common.collect.Collections2;
|
|||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import im.conversations.android.xmpp.model.data.Data;
|
||||
import im.conversations.android.xmpp.model.data.Field;
|
||||
import im.conversations.android.xmpp.model.disco.info.Feature;
|
||||
|
@ -15,7 +16,7 @@ import java.util.Comparator;
|
|||
import java.util.List;
|
||||
|
||||
public final class EntityCapabilities {
|
||||
public static byte[] hash(final InfoQuery info) {
|
||||
public static EntityCapsHash hash(final InfoQuery info) {
|
||||
final StringBuilder s = new StringBuilder();
|
||||
final List<Identity> orderedIdentities =
|
||||
Ordering.from(
|
||||
|
@ -76,7 +77,8 @@ public final class EntityCapabilities {
|
|||
}
|
||||
}
|
||||
}
|
||||
return Hashing.sha1().hashString(s.toString(), StandardCharsets.UTF_8).asBytes();
|
||||
return new EntityCapsHash(
|
||||
Hashing.sha1().hashString(s.toString(), StandardCharsets.UTF_8).asBytes());
|
||||
}
|
||||
|
||||
private static String clean(String s) {
|
||||
|
@ -86,4 +88,23 @@ public final class EntityCapabilities {
|
|||
private static String blankNull(String s) {
|
||||
return s == null ? "" : clean(s);
|
||||
}
|
||||
|
||||
public abstract static class Hash {
|
||||
public final byte[] hash;
|
||||
|
||||
protected Hash(byte[] hash) {
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
public String encoded() {
|
||||
return BaseEncoding.base64().encode(hash);
|
||||
}
|
||||
}
|
||||
|
||||
public static class EntityCapsHash extends Hash {
|
||||
|
||||
protected EntityCapsHash(byte[] hash) {
|
||||
super(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package im.conversations.android.xmpp;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Collections2;
|
||||
|
@ -25,13 +28,28 @@ public class EntityCapabilities2 {
|
|||
|
||||
private static final char FILE_SEPARATOR = 0x1c;
|
||||
|
||||
public static byte[] hash(final InfoQuery info) {
|
||||
return hash(Hashing.sha256(), info);
|
||||
public static EntityCaps2Hash hash(final InfoQuery info) {
|
||||
return hash(Algorithm.SHA_256, info);
|
||||
}
|
||||
|
||||
public static byte[] hash(HashFunction hashFunction, final InfoQuery info) {
|
||||
final String algo = algorithm(info);
|
||||
return hashFunction.hashString(algo, StandardCharsets.UTF_8).asBytes();
|
||||
public static EntityCaps2Hash hash(final Algorithm algorithm, final InfoQuery info) {
|
||||
final String result = algorithm(info);
|
||||
final var hashFunction = toHashFunction(algorithm);
|
||||
return new EntityCaps2Hash(
|
||||
algorithm, hashFunction.hashString(result, StandardCharsets.UTF_8).asBytes());
|
||||
}
|
||||
|
||||
private static HashFunction toHashFunction(final Algorithm algorithm) {
|
||||
switch (algorithm) {
|
||||
case SHA_1:
|
||||
return Hashing.sha1();
|
||||
case SHA_256:
|
||||
return Hashing.sha256();
|
||||
case SHA_512:
|
||||
return Hashing.sha512();
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown hash algorithm");
|
||||
}
|
||||
}
|
||||
|
||||
private static String asHex(final String message) {
|
||||
|
@ -128,4 +146,36 @@ public class EntityCapabilities2 {
|
|||
EntityCapabilities2::extension)))
|
||||
+ FILE_SEPARATOR;
|
||||
}
|
||||
|
||||
public static class EntityCaps2Hash extends EntityCapabilities.Hash {
|
||||
|
||||
public final Algorithm algorithm;
|
||||
|
||||
protected EntityCaps2Hash(final Algorithm algorithm, byte[] hash) {
|
||||
super(hash);
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Algorithm {
|
||||
SHA_1,
|
||||
SHA_256,
|
||||
SHA_512;
|
||||
|
||||
public static Algorithm tryParse(@Nullable final String name) {
|
||||
try {
|
||||
return valueOf(
|
||||
CaseFormat.LOWER_HYPHEN.to(
|
||||
CaseFormat.UPPER_UNDERSCORE, Strings.nullToEmpty(name)));
|
||||
} catch (final IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, super.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,8 +46,8 @@ public class DiscoManager extends AbstractManager {
|
|||
throw new IllegalStateException(
|
||||
"Node in response did not match node in request");
|
||||
}
|
||||
final byte[] caps = EntityCapabilities.hash(infoQuery);
|
||||
final byte[] caps2 = EntityCapabilities2.hash(infoQuery);
|
||||
final byte[] caps = EntityCapabilities.hash(infoQuery).hash;
|
||||
final byte[] caps2 = EntityCapabilities2.hash(infoQuery).hash;
|
||||
getDatabase()
|
||||
.discoDao()
|
||||
.set(getAccount(), entity, node, caps, caps2, infoQuery);
|
||||
|
|
|
@ -3,7 +3,6 @@ package im.conversations.android.xmpp;
|
|||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xml.XmlElementReader;
|
||||
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
||||
|
@ -34,7 +33,7 @@ public class EntityCapabilitiesTest {
|
|||
final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
|
||||
assertThat(element, instanceOf(InfoQuery.class));
|
||||
final InfoQuery info = (InfoQuery) element;
|
||||
final String var = BaseEncoding.base64().encode(EntityCapabilities.hash(info));
|
||||
final String var = EntityCapabilities.hash(info).encoded();
|
||||
Assert.assertEquals("QgayPKawpkPSDYmwT/WM94uAlu0=", var);
|
||||
}
|
||||
|
||||
|
@ -74,7 +73,7 @@ public class EntityCapabilitiesTest {
|
|||
final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
|
||||
assertThat(element, instanceOf(InfoQuery.class));
|
||||
final InfoQuery info = (InfoQuery) element;
|
||||
final String var = BaseEncoding.base64().encode(EntityCapabilities.hash(info));
|
||||
final String var = EntityCapabilities.hash(info).encoded();
|
||||
Assert.assertEquals("q07IKJEyjvHSyhy//CH0CxmKi8w=", var);
|
||||
}
|
||||
|
||||
|
@ -104,7 +103,7 @@ public class EntityCapabilitiesTest {
|
|||
final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
|
||||
assertThat(element, instanceOf(InfoQuery.class));
|
||||
final InfoQuery info = (InfoQuery) element;
|
||||
final String var = BaseEncoding.base64().encode(EntityCapabilities2.hash(info));
|
||||
final String var = EntityCapabilities2.hash(info).encoded();
|
||||
Assert.assertEquals("kzBZbkqJ3ADrj7v08reD1qcWUwNGHaidNUgD7nHpiw8=", var);
|
||||
}
|
||||
|
||||
|
@ -180,7 +179,7 @@ public class EntityCapabilitiesTest {
|
|||
final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
|
||||
assertThat(element, instanceOf(InfoQuery.class));
|
||||
final InfoQuery info = (InfoQuery) element;
|
||||
final String var = BaseEncoding.base64().encode(EntityCapabilities2.hash(info));
|
||||
final String var = EntityCapabilities2.hash(info).encoded();
|
||||
Assert.assertEquals("u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=", var);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue