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 dda3a4d6dc..0579e215b6 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 @@ -97,6 +97,10 @@ object EnvelopeContentValidator { return Result.Invalid("[DataMessage] Invalid ACI on quote body range!") } + if (dataMessage.quote != null && dataMessage.quote.bodyRanges.any { it.isStyleRangeMissingOffsets() }) { + return Result.Invalid("[DataMessage] Style body range on quote is missing a start or length!") + } + if (dataMessage.quote != null && dataMessage.quote.bodyRanges.hasInvalidBounds(dataMessage.quote.text)) { return Result.Invalid("[DataMessage] Quote body range with out-of-bounds start/length!") } @@ -113,6 +117,10 @@ object EnvelopeContentValidator { return Result.Invalid("[DataMessage] Invalid ACI on body range!") } + if (dataMessage.bodyRanges.any { it.isStyleRangeMissingOffsets() }) { + return Result.Invalid("[DataMessage] Style body range is missing a start or length!") + } + if (dataMessage.bodyRanges.hasInvalidBounds(dataMessage.body)) { return Result.Invalid("[DataMessage] Body range with out-of-bounds start/length!") } @@ -363,6 +371,10 @@ object EnvelopeContentValidator { return Result.Invalid("[EditMessage] Invalid UUID on body range!") } + if (dataMessage.bodyRanges.any { it.isStyleRangeMissingOffsets() }) { + return Result.Invalid("[EditMessage] Style body range is missing a start or length!") + } + if (dataMessage.bodyRanges.hasInvalidBounds(dataMessage.body)) { return Result.Invalid("[EditMessage] Body range with out-of-bounds start/length!") } @@ -389,6 +401,10 @@ object EnvelopeContentValidator { } } + private fun BodyRange.isStyleRangeMissingOffsets(): Boolean { + return this.style != null && (this.start == null || this.length == null) + } + private fun AttachmentPointer?.isNullOrInvalid(): Boolean { return this == null || (this.cdnId == null && this.cdnKey == null) } 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 8560f37545..748391dfe9 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 @@ -428,6 +428,71 @@ class EnvelopeContentValidatorTest { assert(result is EnvelopeContentValidator.Result.Valid) } + @Test + fun `validate - ensure style body range missing start is marked invalid`() { + val content = Content( + dataMessage = DataMessage( + timestamp = 1234, + bodyRanges = listOf( + BodyRange(length = 1, style = BodyRange.Style.BOLD) + ) + ) + ) + + val result = EnvelopeContentValidator.validate(Envelope(clientTimestamp = 1234), content, SELF_ACI, CiphertextMessage.WHISPER_TYPE) + assert(result is EnvelopeContentValidator.Result.Invalid) + } + + @Test + fun `validate - ensure style body range missing length is marked invalid`() { + val content = Content( + dataMessage = DataMessage( + timestamp = 1234, + bodyRanges = listOf( + BodyRange(start = 0, style = BodyRange.Style.BOLD) + ) + ) + ) + + val result = EnvelopeContentValidator.validate(Envelope(clientTimestamp = 1234), content, SELF_ACI, CiphertextMessage.WHISPER_TYPE) + assert(result is EnvelopeContentValidator.Result.Invalid) + } + + @Test + fun `validate - ensure style body range with both start and length is marked valid`() { + val content = Content( + dataMessage = DataMessage( + timestamp = 1234, + body = "hello", + bodyRanges = listOf( + BodyRange(start = 0, length = 1, style = BodyRange.Style.BOLD) + ) + ) + ) + + val result = EnvelopeContentValidator.validate(Envelope(clientTimestamp = 1234), content, SELF_ACI, CiphertextMessage.WHISPER_TYPE) + assert(result is EnvelopeContentValidator.Result.Valid) + } + + @Test + fun `validate - ensure quote style body range missing start is marked invalid`() { + val content = Content( + dataMessage = DataMessage( + timestamp = 1234, + quote = DataMessage.Quote( + id = 1000, + authorAci = OTHER_ACI.toString(), + bodyRanges = listOf( + BodyRange(length = 1, style = BodyRange.Style.BOLD) + ) + ) + ) + ) + + val result = EnvelopeContentValidator.validate(Envelope(clientTimestamp = 1234), content, SELF_ACI, CiphertextMessage.WHISPER_TYPE) + assert(result is EnvelopeContentValidator.Result.Invalid) + } + @Test fun `validate - ensure sync blocked with invalid string aci and empty binary list is marked invalid`() { val envelope = Envelope(sourceServiceId = SELF_ACI.toString())