Show toast to internal users for invalid messages.

This commit is contained in:
Greyson Parrelli 2023-05-02 16:38:39 -04:00 committed by Alex Hart
parent ace47c61b1
commit 78b530f8b8
3 changed files with 69 additions and 8 deletions

View file

@ -133,6 +133,11 @@ object MessageDecryptor {
if (validationResult is EnvelopeContentValidator.Result.Invalid) { if (validationResult is EnvelopeContentValidator.Result.Invalid) {
Log.w(TAG, "${logPrefix(envelope, cipherResult)} Invalid content! ${validationResult.reason}", validationResult.throwable) Log.w(TAG, "${logPrefix(envelope, cipherResult)} Invalid content! ${validationResult.reason}", validationResult.throwable)
if (FeatureFlags.internalUser()) {
postInvalidMessageNotification(context, validationResult.reason)
}
return Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations.toUnmodifiableList()) return Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations.toUnmodifiableList())
} }
@ -182,7 +187,7 @@ object MessageDecryptor {
Log.w(TAG, "${logPrefix(envelope, e)} Decryption error!", e, true) Log.w(TAG, "${logPrefix(envelope, e)} Decryption error!", e, true)
if (FeatureFlags.internalUser()) { if (FeatureFlags.internalUser()) {
postErrorNotification(context) postDecryptionErrorNotification(context)
} }
if (FeatureFlags.retryReceipts()) { if (FeatureFlags.retryReceipts()) {
@ -324,11 +329,22 @@ object MessageDecryptor {
} }
} }
private fun postErrorNotification(context: Context) { private fun postDecryptionErrorNotification(context: Context) {
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES) val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_notification) .setSmallIcon(R.drawable.ic_notification)
.setContentTitle(context.getString(R.string.MessageDecryptionUtil_failed_to_decrypt_message)) .setContentTitle("[Internal-only] Failed to decrypt a message!")
.setContentText(context.getString(R.string.MessageDecryptionUtil_tap_to_send_a_debug_log)) .setContentText("Tap to send a debug log")
.setContentIntent(PendingIntent.getActivity(context, 0, Intent(context, SubmitDebugLogActivity::class.java), PendingIntentFlags.mutable()))
.build()
NotificationManagerCompat.from(context).notify(NotificationIds.INTERNAL_ERROR, notification)
}
private fun postInvalidMessageNotification(context: Context, message: String) {
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("[Internal-only] Received an invalid message!")
.setContentText("$message Tap to send a debug log.")
.setContentIntent(PendingIntent.getActivity(context, 0, Intent(context, SubmitDebugLogActivity::class.java), PendingIntentFlags.mutable())) .setContentIntent(PendingIntent.getActivity(context, 0, Intent(context, SubmitDebugLogActivity::class.java), PendingIntentFlags.mutable()))
.build() .build()

View file

@ -1223,10 +1223,6 @@
<string name="MediaRepository_all_media">All media</string> <string name="MediaRepository_all_media">All media</string>
<string name="MediaRepository__camera">Camera</string> <string name="MediaRepository__camera">Camera</string>
<!-- MessageDecryptionUtil -->
<string name="MessageDecryptionUtil_failed_to_decrypt_message">Failed to decrypt message</string>
<string name="MessageDecryptionUtil_tap_to_send_a_debug_log">Tap to send a debug log</string>
<!-- MessageRecord --> <!-- MessageRecord -->
<string name="MessageRecord_unknown">Unknown</string> <string name="MessageRecord_unknown">Unknown</string>
<string name="MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported">Received a message encrypted using an old version of Signal that is no longer supported. Please ask the sender to update to the most recent version and resend the message.</string> <string name="MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported">Received a message encrypted using an old version of Signal that is no longer supported. Please ask the sender to update to the most recent version and resend the message.</string>

View file

@ -26,6 +26,14 @@ import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Typing
object EnvelopeContentValidator { object EnvelopeContentValidator {
fun validate(envelope: Envelope, content: Content): Result { fun validate(envelope: Envelope, content: Content): Result {
if (envelope.type == Envelope.Type.PLAINTEXT_CONTENT) {
val result: Result? = createPlaintextResultIfInvalid(content)
if (result != null) {
return result
}
}
return when { return when {
envelope.story && !content.meetsStoryFlagCriteria() -> Result.Invalid("Envelope was flagged as a story, but it did not have any story-related content!") envelope.story && !content.meetsStoryFlagCriteria() -> Result.Invalid("Envelope was flagged as a story, but it did not have any story-related content!")
content.hasDataMessage() -> validateDataMessage(envelope, content.dataMessage) content.hasDataMessage() -> validateDataMessage(envelope, content.dataMessage)
@ -288,6 +296,47 @@ object EnvelopeContentValidator {
} }
} }
private fun createPlaintextResultIfInvalid(content: Content): Result? {
val errors: MutableList<String> = mutableListOf()
if (!content.hasDecryptionErrorMessage()) {
errors += "Missing DecryptionErrorMessage"
}
if (content.hasStoryMessage()) {
errors += "Unexpected StoryMessage"
}
if (content.hasSenderKeyDistributionMessage()) {
errors += "Unexpected SenderKeyDistributionMessage"
}
if (content.hasCallMessage()) {
errors += "Unexpected CallMessage"
}
if (content.hasEditMessage()) {
errors += "Unexpected EditMessage"
}
if (content.hasNullMessage()) {
errors += "Unexpected NullMessage"
}
if (content.hasPniSignatureMessage()) {
errors += "Unexpected PniSignatureMessage"
}
if (content.hasReceiptMessage()) {
errors += "Unexpected ReceiptMessage"
}
if (content.hasSyncMessage()) {
errors += "Unexpected SyncMessage"
}
if (content.hasTypingMessage()) {
errors += "Unexpected TypingMessage"
}
return if (errors.isNotEmpty()) {
Result.Invalid("Invalid PLAINTEXT_CONTENT! Errors: $errors")
} else {
null
}
}
private fun validateGroupContextV2(groupContext: GroupContextV2, prefix: String): Result.Invalid? { private fun validateGroupContextV2(groupContext: GroupContextV2, prefix: String): Result.Invalid? {
return if (!groupContext.hasMasterKey()) { return if (!groupContext.hasMasterKey()) {
Result.Invalid("$prefix Missing GV2 master key!") Result.Invalid("$prefix Missing GV2 master key!")