mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-20 11:08:05 +01:00
Retire the (unused!) binary message format
This commit is contained in:
committed by
Jon Chambers
parent
aa36dc95ef
commit
e9119da040
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.providers;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.UUID;
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
||||
public abstract class BinaryProviderBase {
|
||||
|
||||
/**
|
||||
* Reads a UUID in network byte order and converts to a UUID object.
|
||||
*/
|
||||
UUID readUuid(InputStream stream) throws IOException {
|
||||
byte[] buffer = new byte[8];
|
||||
|
||||
int read = stream.readNBytes(buffer, 0, 8);
|
||||
if (read != 8) {
|
||||
throw new IOException("Insufficient bytes for UUID");
|
||||
}
|
||||
long msb = convertNetworkByteOrderToLong(buffer);
|
||||
|
||||
read = stream.readNBytes(buffer, 0, 8);
|
||||
if (read != 8) {
|
||||
throw new IOException("Insufficient bytes for UUID");
|
||||
}
|
||||
long lsb = convertNetworkByteOrderToLong(buffer);
|
||||
|
||||
return new UUID(msb, lsb);
|
||||
}
|
||||
|
||||
private long convertNetworkByteOrderToLong(byte[] buffer) {
|
||||
long result = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
result = (result << 8) | (buffer[i] & 0xFFL);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a varint. A varint larger than 64 bits is rejected with a {@code WebApplicationException}. An
|
||||
* {@code IOException} is thrown if the stream ends before we finish reading the varint.
|
||||
*
|
||||
* @return the varint value
|
||||
*/
|
||||
static long readVarint(InputStream stream) throws IOException, WebApplicationException {
|
||||
boolean hasMore = true;
|
||||
int currentOffset = 0;
|
||||
long result = 0;
|
||||
while (hasMore) {
|
||||
if (currentOffset >= 64) {
|
||||
throw new BadRequestException("varint is too large");
|
||||
}
|
||||
int b = stream.read();
|
||||
if (b == -1) {
|
||||
throw new IOException("Missing byte " + (currentOffset / 7) + " of varint");
|
||||
}
|
||||
if (currentOffset == 63 && (b & 0xFE) != 0) {
|
||||
throw new BadRequestException("varint is too large");
|
||||
}
|
||||
hasMore = (b & 0x80) != 0;
|
||||
result |= ((long)(b & 0x7F)) << currentOffset;
|
||||
currentOffset += 7;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads two bytes with most significant byte first. Treats the value as unsigned so the range returned is
|
||||
* {@code [0, 65535]}.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static int readU16(InputStream stream) throws IOException {
|
||||
int b1 = stream.read();
|
||||
if (b1 == -1) {
|
||||
throw new IOException("Missing byte 1 of U16");
|
||||
}
|
||||
int b2 = stream.read();
|
||||
if (b2 == -1) {
|
||||
throw new IOException("Missing byte 2 of U16");
|
||||
}
|
||||
return (b1 << 8) | b2;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.providers;
|
||||
|
||||
import io.dropwizard.util.DataSizeUnit;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.NoContentException;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.MessageBodyReader;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
import org.whispersystems.textsecuregcm.entities.IncomingDeviceMessage;
|
||||
|
||||
@Provider
|
||||
@Consumes(MultiDeviceMessageListProvider.MEDIA_TYPE)
|
||||
public class MultiDeviceMessageListProvider extends BinaryProviderBase implements MessageBodyReader<IncomingDeviceMessage[]> {
|
||||
|
||||
public static final String MEDIA_TYPE = "application/vnd.signal-messenger.mdml";
|
||||
public static final int MAX_MESSAGE_COUNT = 50;
|
||||
public static final int MAX_MESSAGE_SIZE = Math.toIntExact(DataSizeUnit.KIBIBYTES.toBytes(256));
|
||||
public static final byte VERSION = 0x01;
|
||||
|
||||
@Override
|
||||
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
|
||||
return MEDIA_TYPE.equals(mediaType.toString()) && IncomingDeviceMessage[].class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IncomingDeviceMessage[]
|
||||
readFrom(Class<IncomingDeviceMessage[]> resultType, Type genericType,
|
||||
Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
|
||||
InputStream entityStream)
|
||||
throws IOException, WebApplicationException {
|
||||
int versionByte = entityStream.read();
|
||||
if (versionByte == -1) {
|
||||
throw new NoContentException("Empty body not allowed");
|
||||
}
|
||||
if (versionByte != VERSION) {
|
||||
throw new BadRequestException("Unsupported version");
|
||||
}
|
||||
int count = entityStream.read();
|
||||
if (count == -1) {
|
||||
throw new IOException("Missing count");
|
||||
}
|
||||
if (count > MAX_MESSAGE_COUNT) {
|
||||
throw new BadRequestException("Maximum recipient count exceeded");
|
||||
}
|
||||
IncomingDeviceMessage[] messages = new IncomingDeviceMessage[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
long deviceId = readVarint(entityStream);
|
||||
int registrationId = readU16(entityStream);
|
||||
|
||||
int type = entityStream.read();
|
||||
if (type == -1) {
|
||||
throw new IOException("Unexpected end of stream reading message type");
|
||||
}
|
||||
|
||||
long messageLength = readVarint(entityStream);
|
||||
if (messageLength > MAX_MESSAGE_SIZE) {
|
||||
throw new WebApplicationException("Message body too large", Status.REQUEST_ENTITY_TOO_LARGE);
|
||||
}
|
||||
byte[] contents = entityStream.readNBytes(Math.toIntExact(messageLength));
|
||||
if (contents.length != messageLength) {
|
||||
throw new IOException("Unexpected end of stream in the middle of message contents");
|
||||
}
|
||||
|
||||
messages[i] = new IncomingDeviceMessage(type, deviceId, registrationId, contents);
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.whispersystems.textsecuregcm.providers;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.dropwizard.util.DataSizeUnit;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -23,7 +24,7 @@ import org.whispersystems.textsecuregcm.entities.MultiRecipientMessage;
|
||||
|
||||
@Provider
|
||||
@Consumes(MultiRecipientMessageProvider.MEDIA_TYPE)
|
||||
public class MultiRecipientMessageProvider extends BinaryProviderBase implements MessageBodyReader<MultiRecipientMessage> {
|
||||
public class MultiRecipientMessageProvider implements MessageBodyReader<MultiRecipientMessage> {
|
||||
|
||||
public static final String MEDIA_TYPE = "application/vnd.signal-messenger.mrm";
|
||||
public static final int MAX_RECIPIENT_COUNT = 5000;
|
||||
@@ -70,4 +71,78 @@ public class MultiRecipientMessageProvider extends BinaryProviderBase implements
|
||||
}
|
||||
return new MultiRecipientMessage(recipients, commonPayload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a UUID in network byte order and converts to a UUID object.
|
||||
*/
|
||||
private UUID readUuid(InputStream stream) throws IOException {
|
||||
byte[] buffer = new byte[8];
|
||||
|
||||
int read = stream.readNBytes(buffer, 0, 8);
|
||||
if (read != 8) {
|
||||
throw new IOException("Insufficient bytes for UUID");
|
||||
}
|
||||
long msb = convertNetworkByteOrderToLong(buffer);
|
||||
|
||||
read = stream.readNBytes(buffer, 0, 8);
|
||||
if (read != 8) {
|
||||
throw new IOException("Insufficient bytes for UUID");
|
||||
}
|
||||
long lsb = convertNetworkByteOrderToLong(buffer);
|
||||
|
||||
return new UUID(msb, lsb);
|
||||
}
|
||||
|
||||
private long convertNetworkByteOrderToLong(byte[] buffer) {
|
||||
long result = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
result = (result << 8) | (buffer[i] & 0xFFL);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a varint. A varint larger than 64 bits is rejected with a {@code WebApplicationException}. An
|
||||
* {@code IOException} is thrown if the stream ends before we finish reading the varint.
|
||||
*
|
||||
* @return the varint value
|
||||
*/
|
||||
private long readVarint(InputStream stream) throws IOException, WebApplicationException {
|
||||
boolean hasMore = true;
|
||||
int currentOffset = 0;
|
||||
int result = 0;
|
||||
while (hasMore) {
|
||||
if (currentOffset >= 64) {
|
||||
throw new BadRequestException("varint is too large");
|
||||
}
|
||||
int b = stream.read();
|
||||
if (b == -1) {
|
||||
throw new IOException("Missing byte " + (currentOffset / 7) + " of varint");
|
||||
}
|
||||
if (currentOffset == 63 && (b & 0xFE) != 0) {
|
||||
throw new BadRequestException("varint is too large");
|
||||
}
|
||||
hasMore = (b & 0x80) != 0;
|
||||
result |= (b & 0x7F) << currentOffset;
|
||||
currentOffset += 7;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads two bytes with most significant byte first. Treats the value as unsigned so the range returned is
|
||||
* {@code [0, 65535]}.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static int readU16(InputStream stream) throws IOException {
|
||||
int b1 = stream.read();
|
||||
if (b1 == -1) {
|
||||
throw new IOException("Missing byte 1 of U16");
|
||||
}
|
||||
int b2 = stream.read();
|
||||
if (b2 == -1) {
|
||||
throw new IOException("Missing byte 2 of U16");
|
||||
}
|
||||
return (b1 << 8) | b2;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user