Validate style body ranges have a start and length to prevent message processing crash.

This commit is contained in:
Greyson Parrelli
2026-06-05 20:04:55 +00:00
committed by Cody Henthorne
parent 848a61787b
commit 798ba11e62
2 changed files with 81 additions and 0 deletions
@@ -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)
}
@@ -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())