mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 22:28:03 +01:00
Prepare to read profile data stored as byte arrays
This commit is contained in:
@@ -8,7 +8,6 @@ package org.whispersystems.textsecuregcm.storage;
|
||||
import static org.whispersystems.textsecuregcm.metrics.MetricsUtil.name;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.Timer;
|
||||
import java.util.ArrayList;
|
||||
@@ -77,12 +76,7 @@ public class Profiles {
|
||||
private static final Timer SET_PROFILES_TIMER = Metrics.timer(name(Profiles.class, "set"));
|
||||
private static final Timer GET_PROFILE_TIMER = Metrics.timer(name(Profiles.class, "get"));
|
||||
private static final Timer DELETE_PROFILES_TIMER = Metrics.timer(name(Profiles.class, "delete"));
|
||||
|
||||
private static final Counter INVALID_NAME_COUNTER = Metrics.counter(name(Profiles.class, "invalidProfileData"), "field", "name");
|
||||
private static final Counter INVALID_EMOJI_COUNTER = Metrics.counter(name(Profiles.class, "invalidProfileData"), "field", "emoji");
|
||||
private static final Counter INVALID_ABOUT_COUNTER = Metrics.counter(name(Profiles.class, "invalidProfileData"), "field", "about");
|
||||
private static final Counter INVALID_PAYMENT_ADDRESS_COUNTER = Metrics.counter(name(Profiles.class, "invalidProfileData"), "field", "paymentAddress");
|
||||
|
||||
private static final String PARSE_BYTE_ARRAY_COUNTER_NAME = name(Profiles.class, "parseByteArray");
|
||||
|
||||
public Profiles(final DynamoDbClient dynamoDbClient,
|
||||
final DynamoDbAsyncClient dynamoDbAsyncClient,
|
||||
@@ -232,34 +226,23 @@ public class Profiles {
|
||||
}
|
||||
|
||||
private static VersionedProfile fromItem(final Map<String, AttributeValue> item) {
|
||||
final String name = AttributeValues.getString(item, ATTR_NAME, null);
|
||||
final String emoji = AttributeValues.getString(item, ATTR_EMOJI, null);
|
||||
final String about = AttributeValues.getString(item, ATTR_ABOUT, null);
|
||||
final String paymentAddress = AttributeValues.getString(item, ATTR_PAYMENT_ADDRESS, null);
|
||||
|
||||
checkValidBase64(name, INVALID_NAME_COUNTER);
|
||||
checkValidBase64(emoji, INVALID_EMOJI_COUNTER);
|
||||
checkValidBase64(about, INVALID_ABOUT_COUNTER);
|
||||
checkValidBase64(paymentAddress, INVALID_PAYMENT_ADDRESS_COUNTER);
|
||||
|
||||
return new VersionedProfile(
|
||||
AttributeValues.getString(item, ATTR_VERSION, null),
|
||||
name,
|
||||
getBase64EncodedBytes(item, ATTR_NAME, PARSE_BYTE_ARRAY_COUNTER_NAME),
|
||||
AttributeValues.getString(item, ATTR_AVATAR, null),
|
||||
emoji,
|
||||
about,
|
||||
paymentAddress,
|
||||
getBase64EncodedBytes(item, ATTR_EMOJI, PARSE_BYTE_ARRAY_COUNTER_NAME),
|
||||
getBase64EncodedBytes(item, ATTR_ABOUT, PARSE_BYTE_ARRAY_COUNTER_NAME),
|
||||
getBase64EncodedBytes(item, ATTR_PAYMENT_ADDRESS, PARSE_BYTE_ARRAY_COUNTER_NAME),
|
||||
AttributeValues.getByteArray(item, ATTR_COMMITMENT, null));
|
||||
}
|
||||
|
||||
private static void checkValidBase64(final String value, final Counter counter) {
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
try {
|
||||
Base64.getDecoder().decode(value);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
counter.increment();
|
||||
}
|
||||
private static String getBase64EncodedBytes(final Map<String, AttributeValue> item, final String attributeName, final String counterName) {
|
||||
final AttributeValue attributeValue = item.get(attributeName);
|
||||
|
||||
if (attributeValue == null) {
|
||||
return null;
|
||||
}
|
||||
return Base64.getEncoder().encodeToString(AttributeValues.extractByteArray(attributeValue, counterName));
|
||||
}
|
||||
|
||||
public void deleteAll(final UUID uuid) {
|
||||
|
||||
@@ -14,7 +14,10 @@ import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.whispersystems.textsecuregcm.metrics.MetricsUtil.name;
|
||||
|
||||
public class SingleUseECPreKeyStore extends SingleUsePreKeyStore<ECPreKey> {
|
||||
private static final String PARSE_BYTE_ARRAY_COUNTER_NAME = name(SingleUseECPreKeyStore.class, "parseByteArray");
|
||||
|
||||
protected SingleUseECPreKeyStore(final DynamoDbAsyncClient dynamoDbAsyncClient, final String tableName) {
|
||||
super(dynamoDbAsyncClient, tableName);
|
||||
@@ -31,7 +34,7 @@ public class SingleUseECPreKeyStore extends SingleUsePreKeyStore<ECPreKey> {
|
||||
@Override
|
||||
protected ECPreKey getPreKeyFromItem(final Map<String, AttributeValue> item) {
|
||||
final long keyId = item.get(KEY_DEVICE_ID_KEY_ID).b().asByteBuffer().getLong(8);
|
||||
final byte[] publicKey = extractByteArray(item.get(ATTR_PUBLIC_KEY));
|
||||
final byte[] publicKey = AttributeValues.extractByteArray(item.get(ATTR_PUBLIC_KEY), PARSE_BYTE_ARRAY_COUNTER_NAME);
|
||||
|
||||
try {
|
||||
return new ECPreKey(keyId, new ECPublicKey(publicKey));
|
||||
|
||||
@@ -73,9 +73,6 @@ public abstract class SingleUsePreKeyStore<K extends PreKey<?>> {
|
||||
private final String takeKeyTimerName = name(getClass(), "takeKey");
|
||||
private static final String KEY_PRESENT_TAG_NAME = "keyPresent";
|
||||
|
||||
private final Counter parseBytesFromStringCounter = Metrics.counter(name(getClass(), "parseByteArray"), "format", "string");
|
||||
private final Counter readBytesFromByteArrayCounter = Metrics.counter(name(getClass(), "parseByteArray"), "format", "bytes");
|
||||
|
||||
static final String KEY_ACCOUNT_UUID = "U";
|
||||
static final String KEY_DEVICE_ID_KEY_ID = "DK";
|
||||
static final String ATTR_PUBLIC_KEY = "P";
|
||||
@@ -289,24 +286,4 @@ public abstract class SingleUsePreKeyStore<K extends PreKey<?>> {
|
||||
final K preKey);
|
||||
|
||||
protected abstract K getPreKeyFromItem(final Map<String, AttributeValue> item);
|
||||
|
||||
/**
|
||||
* Extracts a byte array from an {@link AttributeValue} that may be either a byte array or a base64-encoded string.
|
||||
*
|
||||
* @param attributeValue the {@code AttributeValue} from which to extract a byte array
|
||||
*
|
||||
* @return the byte array represented by the given {@code AttributeValue}
|
||||
*/
|
||||
@VisibleForTesting
|
||||
byte[] extractByteArray(final AttributeValue attributeValue) {
|
||||
if (attributeValue.b() != null) {
|
||||
readBytesFromByteArrayCounter.increment();
|
||||
return attributeValue.b().asByteArray();
|
||||
} else if (StringUtils.isNotBlank(attributeValue.s())) {
|
||||
parseBytesFromStringCounter.increment();
|
||||
return Base64.getDecoder().decode(attributeValue.s());
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Attribute value has neither a byte array nor a string value");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,13 @@
|
||||
package org.whispersystems.textsecuregcm.util;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import software.amazon.awssdk.core.SdkBytes;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
||||
|
||||
@@ -124,4 +128,24 @@ public class AttributeValues {
|
||||
public static UUID getUUID(Map<String, AttributeValue> item, String key, UUID defaultValue) {
|
||||
return AttributeValues.get(item, key).filter(av -> av.b() != null).map(AttributeValues::toUUID).orElse(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a byte array from an {@link AttributeValue} that may be either a byte array or a base64-encoded string.
|
||||
*
|
||||
* @param attributeValue the {@code AttributeValue} from which to extract a byte array
|
||||
*
|
||||
* @return the byte array represented by the given {@code AttributeValue}
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static byte[] extractByteArray(final AttributeValue attributeValue, final String counterName) {
|
||||
if (attributeValue.b() != null) {
|
||||
Metrics.counter(counterName, "format", "bytes").increment();
|
||||
return attributeValue.b().asByteArray();
|
||||
} else if (StringUtils.isNotBlank(attributeValue.s())) {
|
||||
Metrics.counter(counterName, "format", "string").increment();
|
||||
return Base64.getDecoder().decode(attributeValue.s());
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Attribute value has neither a byte array nor a string value");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user