mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-07-13 17:23:56 +01:00
Fix incorrect type value being used for unknown storage records.
This commit is contained in:
committed by
Nicholas Tinsley
parent
1f2bfe8245
commit
6c4ebc9f58
+12
-4
@@ -1,5 +1,7 @@
|
||||
package org.whispersystems.signalservice.api.storage;
|
||||
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.MessageRequestResponseMessage;
|
||||
import org.whispersystems.signalservice.api.util.ProtoUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.ManifestRecord;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.StorageManifest;
|
||||
|
||||
@@ -87,10 +89,16 @@ public class SignalStorageManifest {
|
||||
List<ManifestRecord.Identifier> ids = new ArrayList<>(storageIds.size());
|
||||
|
||||
for (StorageId id : storageIds) {
|
||||
ids.add(new ManifestRecord.Identifier.Builder()
|
||||
.type(ManifestRecord.Identifier.Type.Companion.fromValue(id.getType()))
|
||||
.raw(ByteString.of(id.getRaw()))
|
||||
.build());
|
||||
ManifestRecord.Identifier.Type type = ManifestRecord.Identifier.Type.Companion.fromValue(id.getType());
|
||||
if (type != null) {
|
||||
ids.add(new ManifestRecord.Identifier.Builder()
|
||||
.type(type)
|
||||
.raw(ByteString.of(id.getRaw()))
|
||||
.build());
|
||||
} else {
|
||||
ByteString unknownEnum = ProtoUtil.writeUnknownEnumValue(StorageRecordProtoUtil.STORAGE_ID_TYPE_TAG, id.getType());
|
||||
ids.add(new ManifestRecord.Identifier(ByteString.of(id.getRaw()), ManifestRecord.Identifier.Type.UNKNOWN, unknownEnum));
|
||||
}
|
||||
}
|
||||
|
||||
ManifestRecord manifestRecord = new ManifestRecord.Builder()
|
||||
|
||||
+5
-1
@@ -3,6 +3,7 @@ package org.whispersystems.signalservice.api.storage;
|
||||
import org.signal.libsignal.protocol.InvalidKeyException;
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
|
||||
import org.whispersystems.signalservice.api.util.ProtoUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.ManifestRecord;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.StorageItem;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.StorageManifest;
|
||||
@@ -24,7 +25,10 @@ public final class SignalStorageModels {
|
||||
List<StorageId> ids = new ArrayList<>(manifestRecord.identifiers.size());
|
||||
|
||||
for (ManifestRecord.Identifier id : manifestRecord.identifiers) {
|
||||
ids.add(StorageId.forType(id.raw.toByteArray(), id.type.getValue()));
|
||||
int typeValue = (id.type != ManifestRecord.Identifier.Type.UNKNOWN) ? id.type.getValue()
|
||||
: ProtoUtil.getUnknownEnumValue(id, StorageRecordProtoUtil.STORAGE_ID_TYPE_TAG);
|
||||
|
||||
ids.add(StorageId.forType(id.raw.toByteArray(), typeValue));
|
||||
}
|
||||
|
||||
return new SignalStorageManifest(manifestRecord.version, manifestRecord.sourceDevice, ids);
|
||||
|
||||
+1
-11
@@ -58,23 +58,13 @@ public class StorageId {
|
||||
|
||||
public static boolean isKnownType(int val) {
|
||||
for (ManifestRecord.Identifier.Type type : ManifestRecord.Identifier.Type.values()) {
|
||||
if (type.getValue() == val) {
|
||||
if (type != ManifestRecord.Identifier.Type.UNKNOWN && type.getValue() == val) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int largestKnownType() {
|
||||
int max = 0;
|
||||
|
||||
for (ManifestRecord.Identifier.Type type : ManifestRecord.Identifier.Type.values()) {
|
||||
max = Math.max(type.getValue(), max);
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
+4
@@ -13,6 +13,10 @@ import org.whispersystems.signalservice.internal.storage.protos.AccountRecord
|
||||
* Provide helpers for various Storage Service protos.
|
||||
*/
|
||||
object StorageRecordProtoUtil {
|
||||
|
||||
/** Must match tag value specified for ManifestRecord.Identifier#type in StorageService.proto */
|
||||
const val STORAGE_ID_TYPE_TAG = 2
|
||||
|
||||
@JvmStatic
|
||||
val defaultAccountRecord by lazy { AccountRecord() }
|
||||
}
|
||||
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
package org.whispersystems.signalservice.api.util;
|
||||
|
||||
import com.squareup.wire.Message;
|
||||
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
public final class ProtoUtil {
|
||||
|
||||
private static final String TAG = ProtoUtil.class.getSimpleName();
|
||||
|
||||
private static final String DEFAULT_INSTANCE = "DEFAULT_INSTANCE";
|
||||
|
||||
private ProtoUtil() {}
|
||||
|
||||
/**
|
||||
* True if there are unknown fields anywhere inside the proto or its nested protos.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static boolean hasUnknownFields(Message rootProto) {
|
||||
List<Message> allProtos = getInnerProtos(rootProto);
|
||||
allProtos.add(rootProto);
|
||||
|
||||
for (Message proto : allProtos) {
|
||||
ByteString unknownFields = proto.unknownFields();
|
||||
|
||||
if (unknownFields.size() > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively retrieves all inner complex proto types inside a given proto.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static List<Message> getInnerProtos(Message proto) {
|
||||
List<Message> innerProtos = new LinkedList<>();
|
||||
|
||||
try {
|
||||
Field[] fields = proto.getClass().getDeclaredFields();
|
||||
|
||||
for (Field field : fields) {
|
||||
if (!field.getName().equals(DEFAULT_INSTANCE) && Message.class.isAssignableFrom(field.getType())) {
|
||||
field.setAccessible(true);
|
||||
|
||||
Message inner = (Message) field.get(proto);
|
||||
if (inner != null) {
|
||||
innerProtos.add(inner);
|
||||
innerProtos.addAll(getInnerProtos(inner));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.w(TAG, "Failed to get inner protos!", e);
|
||||
}
|
||||
|
||||
return innerProtos;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@file:JvmName("ProtoUtil")
|
||||
|
||||
package org.whispersystems.signalservice.api.util
|
||||
|
||||
import com.squareup.wire.FieldEncoding
|
||||
import com.squareup.wire.Message
|
||||
import com.squareup.wire.ProtoAdapter
|
||||
import com.squareup.wire.ProtoReader
|
||||
import com.squareup.wire.ProtoWriter
|
||||
import okio.Buffer
|
||||
import okio.ByteString
|
||||
import org.signal.libsignal.protocol.logging.Log
|
||||
import java.util.LinkedList
|
||||
|
||||
object ProtoUtil {
|
||||
private val TAG = ProtoUtil::class.java.simpleName
|
||||
|
||||
/**
|
||||
* True if there are unknown fields anywhere inside the proto or its nested protos.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun hasUnknownFields(rootProto: Message<*, *>): Boolean {
|
||||
val allProtos = getInnerProtos(rootProto)
|
||||
allProtos.add(rootProto)
|
||||
for (proto in allProtos) {
|
||||
val unknownFields = proto.unknownFields
|
||||
if (unknownFields.size > 0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getUnknownEnumValue(proto: Message<*, *>, tag: Int): Int {
|
||||
val reader = ProtoReader(Buffer().write(proto.unknownFields))
|
||||
reader.forEachTag { unknownTag ->
|
||||
if (unknownTag == tag) {
|
||||
return ProtoAdapter.INT32.decode(reader)
|
||||
}
|
||||
}
|
||||
|
||||
throw AssertionError("Tag $tag not found in unknown fields")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun writeUnknownEnumValue(tag: Int, enumValue: Int): ByteString {
|
||||
val buffer = Buffer()
|
||||
val writer = ProtoWriter(buffer)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(FieldEncoding.VARINT.rawProtoAdapter() as ProtoAdapter<Any>).encodeWithTag(writer, tag, enumValue.toLong())
|
||||
|
||||
return buffer.readByteString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively retrieves all inner complex proto types inside a given proto.
|
||||
*/
|
||||
private fun getInnerProtos(proto: Message<*, *>): MutableList<Message<*, *>> {
|
||||
val innerProtos: MutableList<Message<*, *>> = LinkedList()
|
||||
try {
|
||||
val fields = proto.javaClass.declaredFields
|
||||
for (field in fields) {
|
||||
if (Message::class.java.isAssignableFrom(field.type)) {
|
||||
field.isAccessible = true
|
||||
val inner = field[proto] as? Message<*, *>
|
||||
if (inner != null) {
|
||||
innerProtos.add(inner)
|
||||
innerProtos.addAll(getInnerProtos(inner))
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: IllegalAccessException) {
|
||||
Log.w(TAG, "Failed to get inner protos!", e)
|
||||
}
|
||||
return innerProtos
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user