From 9804c6cf5ea6ab5d570f6b9df2a0d3c5c9d7e761 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Fri, 24 Jul 2026 11:44:38 -0400 Subject: [PATCH] Improve call message validations. --- .../api/messages/EnvelopeContentValidator.kt | 11 +++++- .../messages/EnvelopeContentValidatorTest.kt | 37 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt b/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt index 94fef3b7ea..b6ec0c655b 100644 --- a/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt +++ b/lib/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidator.kt @@ -11,6 +11,7 @@ import org.signal.libsignal.zkgroup.groups.GroupMasterKey import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialPresentation import org.whispersystems.signalservice.internal.push.AttachmentPointer import org.whispersystems.signalservice.internal.push.BodyRange +import org.whispersystems.signalservice.internal.push.CallMessage import org.whispersystems.signalservice.internal.push.Content import org.whispersystems.signalservice.internal.push.DataMessage import org.whispersystems.signalservice.internal.push.EditMessage @@ -61,7 +62,7 @@ object EnvelopeContentValidator { envelope.story == true && !content.meetsStoryFlagCriteria() -> Result.Invalid("Envelope was flagged as a story, but it did not have any story-related content!") content.dataMessage != null -> validateDataMessage(envelope, content.dataMessage) content.syncMessage != null -> validateSyncMessage(envelope, content.syncMessage, localAci) - content.callMessage != null -> Result.Valid + content.callMessage != null -> validateCallMessage(content.callMessage) content.nullMessage != null -> Result.Valid content.receiptMessage != null -> validateReceiptMessage(content.receiptMessage) content.typingMessage != null -> validateTypingMessage(envelope, content.typingMessage) @@ -207,6 +208,14 @@ object EnvelopeContentValidator { return this.options.size < MIN_POLL_OPTIONS || this.options.any { option -> option.length > MAX_POLL_CHARACTER_LENGTH } } + private fun validateCallMessage(callMessage: CallMessage): Result { + if (callMessage.hangup != null && callMessage.hangup.type == null) { + return Result.Invalid("[CallMessage] Missing type on CallMessage.hangup!") + } + + return Result.Valid + } + private fun validateSyncMessage(envelope: Envelope, syncMessage: SyncMessage, localAci: ACI): Result { // Source serviceId was already determined to be a valid serviceId in general val sourceServiceId = ServiceId.parseOrThrow(envelope.sourceServiceId, envelope.sourceServiceIdBinary) diff --git a/lib/libsignal-service/src/test/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidatorTest.kt b/lib/libsignal-service/src/test/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidatorTest.kt index 545241bf9a..14cc4be3f0 100644 --- a/lib/libsignal-service/src/test/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidatorTest.kt +++ b/lib/libsignal-service/src/test/java/org/whispersystems/signalservice/api/messages/EnvelopeContentValidatorTest.kt @@ -12,6 +12,7 @@ import org.signal.libsignal.protocol.message.CiphertextMessage import org.signal.libsignal.protocol.message.DecryptionErrorMessage import org.whispersystems.signalservice.internal.push.AttachmentPointer import org.whispersystems.signalservice.internal.push.BodyRange +import org.whispersystems.signalservice.internal.push.CallMessage import org.whispersystems.signalservice.internal.push.Content import org.whispersystems.signalservice.internal.push.DataMessage import org.whispersystems.signalservice.internal.push.EditMessage @@ -1102,4 +1103,40 @@ class EnvelopeContentValidatorTest { val result = EnvelopeContentValidator.validate(envelope, content, SELF_ACI, CiphertextMessage.WHISPER_TYPE) assert(result is EnvelopeContentValidator.Result.Valid) } + + @Test + fun `validate - ensure call message hangup without a type is marked invalid`() { + val content = Content( + callMessage = CallMessage( + hangup = CallMessage.Hangup(id = 1) + ) + ) + + val result = EnvelopeContentValidator.validate(Envelope(), content, SELF_ACI, CiphertextMessage.WHISPER_TYPE) + assert(result is EnvelopeContentValidator.Result.Invalid) + } + + @Test + fun `validate - ensure call message hangup with a type is marked valid`() { + val content = Content( + callMessage = CallMessage( + hangup = CallMessage.Hangup(id = 1, type = CallMessage.Hangup.Type.HANGUP_NORMAL) + ) + ) + + val result = EnvelopeContentValidator.validate(Envelope(), content, SELF_ACI, CiphertextMessage.WHISPER_TYPE) + assert(result is EnvelopeContentValidator.Result.Valid) + } + + @Test + fun `validate - ensure call message without a hangup is marked valid`() { + val content = Content( + callMessage = CallMessage( + busy = CallMessage.Busy(id = 1) + ) + ) + + val result = EnvelopeContentValidator.validate(Envelope(), content, SELF_ACI, CiphertextMessage.WHISPER_TYPE) + assert(result is EnvelopeContentValidator.Result.Valid) + } }