diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java index 551742c9da..b9b247adb5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java @@ -99,7 +99,8 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr Optional.fromNullable(IncomingMessageObserver.getUnidentifiedPipe()), Optional.of(new SecurityEventListener(context)), provideClientZkOperations().getProfileOperations(), - SignalExecutors.newCachedBoundedExecutor("signal-messages", 1, 16)); + SignalExecutors.newCachedBoundedExecutor("signal-messages", 1, 16), + FeatureFlags.maxEnvelopeSize()); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java index 4fff992027..9e039b615a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java @@ -60,6 +60,7 @@ public final class FeatureFlags { public static final String RESEARCH_MEGAPHONE_1 = "research.megaphone.1"; public static final String MODERN_PROFILE_SHARING = "android.modernProfileSharing"; private static final String VIEWED_RECEIPTS = "android.viewed.receipts"; + private static final String MAX_ENVELOPE_SIZE = "android.maxEnvelopeSize"; /** * We will only store remote values for flags in this set. If you want a flag to be controllable @@ -77,7 +78,8 @@ public final class FeatureFlags { CLIENT_EXPIRATION, RESEARCH_MEGAPHONE_1, MODERN_PROFILE_SHARING, - VIEWED_RECEIPTS + VIEWED_RECEIPTS, + MAX_ENVELOPE_SIZE ); /** @@ -245,13 +247,16 @@ public final class FeatureFlags { return getBoolean(MODERN_PROFILE_SHARING, false); } - /** - * Whether the user should display the content revealed dot in voice notes. - */ + /** Whether the user should display the content revealed dot in voice notes. */ public static boolean viewedReceipts() { return getBoolean(VIEWED_RECEIPTS, false); } + /** The max size envelope that is allowed to be sent. */ + public static int maxEnvelopeSize() { + return getInteger(MAX_ENVELOPE_SIZE, 0); + } + /** Only for rendering debug info. */ public static synchronized @NonNull Map getMemoryValues() { return new TreeMap<>(REMOTE_VALUES); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/ContentTooLargeException.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/ContentTooLargeException.java new file mode 100644 index 0000000000..de734d8d20 --- /dev/null +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/ContentTooLargeException.java @@ -0,0 +1,7 @@ +package org.whispersystems.signalservice.api; + +public class ContentTooLargeException extends IllegalStateException { + public ContentTooLargeException(long size) { + super("Too large! Size: " + size + " bytes"); + } +} diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java index 38082bf4d4..107655c216 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java @@ -126,6 +126,7 @@ public class SignalServiceMessageSender { private final AtomicBoolean isMultiDevice; private final ExecutorService executor; + private final int maxEnvelopeSize; /** * Construct a SignalServiceMessageSender. @@ -149,7 +150,7 @@ public class SignalServiceMessageSender { ClientZkProfileOperations clientZkProfileOperations, ExecutorService executor) { - this(urls, new StaticCredentialsProvider(uuid, e164, password, null), store, signalAgent, isMultiDevice, pipe, unidentifiedPipe, eventListener, clientZkProfileOperations, executor); + this(urls, new StaticCredentialsProvider(uuid, e164, password, null), store, signalAgent, isMultiDevice, pipe, unidentifiedPipe, eventListener, clientZkProfileOperations, executor, 0); } public SignalServiceMessageSender(SignalServiceConfiguration urls, @@ -161,7 +162,8 @@ public class SignalServiceMessageSender { Optional unidentifiedPipe, Optional eventListener, ClientZkProfileOperations clientZkProfileOperations, - ExecutorService executor) + ExecutorService executor, + int maxEnvelopeSize) { this.socket = new PushServiceSocket(urls, credentialsProvider, signalAgent, clientZkProfileOperations); this.store = store; @@ -171,6 +173,7 @@ public class SignalServiceMessageSender { this.isMultiDevice = new AtomicBoolean(isMultiDevice); this.eventListener = eventListener; this.executor = executor != null ? executor : Executors.newSingleThreadExecutor(); + this.maxEnvelopeSize = maxEnvelopeSize; } /** @@ -698,7 +701,13 @@ public class SignalServiceMessageSender { builder.setTimestamp(message.getTimestamp()); - return container.setDataMessage(builder).build().toByteArray(); + byte[] content = container.setDataMessage(builder).build().toByteArray(); + + if (maxEnvelopeSize > 0 && content.length > maxEnvelopeSize) { + throw new ContentTooLargeException(content.length); + } + + return content; } private byte[] createCallContent(SignalServiceCallMessage callMessage) {