mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-12-18 07:11:58 +03:00
Merge pull request #8170 from vector-im/feature/fre/apply_push_rules_after_decryption
Reapply push rules on the decrypted event source (PSG-1146)
This commit is contained in:
commit
39c702f41b
7 changed files with 122 additions and 16 deletions
1
changelog.d/8170.bugfix
Normal file
1
changelog.d/8170.bugfix
Normal file
|
@ -0,0 +1 @@
|
|||
Reapply local push rules after event decryption
|
|
@ -39,8 +39,17 @@ class EventMatchCondition(
|
|||
override fun technicalDescription() = "'$key' matches '$pattern'"
|
||||
|
||||
fun isSatisfied(event: Event): Boolean {
|
||||
// TODO encrypted events?
|
||||
val rawJson = MoshiProvider.providesMoshi().adapter(Event::class.java).toJsonValue(event) as? Map<*, *>
|
||||
val rawJson: Map<*, *> = (MoshiProvider.providesMoshi().adapter(Event::class.java).toJsonValue(event) as? Map<*, *>)
|
||||
?.let { rawJson ->
|
||||
val decryptedRawJson = event.mxDecryptionResult?.payload
|
||||
if (decryptedRawJson != null) {
|
||||
rawJson
|
||||
.toMutableMap()
|
||||
.apply { putAll(decryptedRawJson) }
|
||||
} else {
|
||||
rawJson
|
||||
}
|
||||
}
|
||||
?: return false
|
||||
val value = extractField(rawJson, key) ?: return false
|
||||
|
||||
|
|
|
@ -94,7 +94,10 @@ internal class EventDecryptor @Inject constructor(
|
|||
* @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
|
||||
*/
|
||||
suspend fun decryptEventAndSaveResult(event: Event, timeline: String) {
|
||||
tryOrNull(message = "Unable to decrypt the event") {
|
||||
// event is not encrypted or already decrypted
|
||||
if (event.getClearType() != EventType.ENCRYPTED) return
|
||||
|
||||
tryOrNull(message = "decryptEventAndSaveResult | Unable to decrypt the event") {
|
||||
decryptEvent(event, timeline)
|
||||
}
|
||||
?.let { result ->
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.session.events.model.isInvitation
|
|||
import org.matrix.android.sdk.api.session.pushrules.PushEvents
|
||||
import org.matrix.android.sdk.api.session.pushrules.rest.PushRule
|
||||
import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse
|
||||
import org.matrix.android.sdk.internal.crypto.EventDecryptor
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import timber.log.Timber
|
||||
|
@ -36,21 +37,22 @@ internal interface ProcessEventForPushTask : Task<ProcessEventForPushTask.Params
|
|||
internal class DefaultProcessEventForPushTask @Inject constructor(
|
||||
private val defaultPushRuleService: DefaultPushRuleService,
|
||||
private val pushRuleFinder: PushRuleFinder,
|
||||
@UserId private val userId: String
|
||||
@UserId private val userId: String,
|
||||
private val eventDecryptor: EventDecryptor,
|
||||
) : ProcessEventForPushTask {
|
||||
|
||||
override suspend fun execute(params: ProcessEventForPushTask.Params) {
|
||||
val newJoinEvents = params.syncResponse.join
|
||||
.mapNotNull { (key, value) ->
|
||||
value.timeline?.events?.mapNotNull {
|
||||
it.takeIf { !it.isInvitation() }?.copy(roomId = key)
|
||||
it.takeIf { !it.isInvitation() }?.copyAll(roomId = key)
|
||||
}
|
||||
}
|
||||
.flatten()
|
||||
|
||||
val inviteEvents = params.syncResponse.invite
|
||||
.mapNotNull { (key, value) ->
|
||||
value.inviteState?.events?.map { it.copy(roomId = key) }
|
||||
value.inviteState?.events?.map { it.copyAll(roomId = key) }
|
||||
}
|
||||
.flatten()
|
||||
|
||||
|
|
|
@ -437,6 +437,10 @@ internal class RoomSyncHandler @Inject constructor(
|
|||
if (event.isEncrypted() && !isInitialSync) {
|
||||
try {
|
||||
decryptIfNeeded(event, roomId)
|
||||
// share the decryption result with the rawEvent because the decryption is done on a copy containing the roomId, see previous comment
|
||||
rawEvent.mxDecryptionResult = event.mxDecryptionResult
|
||||
rawEvent.mCryptoError = event.mCryptoError
|
||||
rawEvent.mCryptoErrorReason = event.mCryptoErrorReason
|
||||
} catch (e: InterruptedException) {
|
||||
Timber.i("Decryption got interrupted")
|
||||
}
|
||||
|
|
|
@ -23,7 +23,11 @@ import org.junit.Assert.assertFalse
|
|||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.MatrixTest
|
||||
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.room.members.MembershipService
|
||||
|
@ -38,15 +42,40 @@ class PushRulesConditionTest : MatrixTest {
|
|||
* Test EventMatchCondition
|
||||
* ========================================================================================== */
|
||||
|
||||
private fun createFakeEncryptedEvent() = Event(
|
||||
type = EventType.ENCRYPTED,
|
||||
eventId = "mx0",
|
||||
roomId = "!fakeRoom",
|
||||
content = EncryptedEventContent(
|
||||
algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
|
||||
ciphertext = "AwgBEpACQEKOkd4Gp0+gSXG4M+btcrnPgsF23xs/lUmS2I4YjmqF...",
|
||||
sessionId = "TO2G4u2HlnhtbIJk",
|
||||
senderKey = "5e3EIqg3JfooZnLQ2qHIcBarbassQ4qXblai0",
|
||||
deviceId = "FAKEE"
|
||||
).toContent()
|
||||
)
|
||||
|
||||
private fun createSimpleTextEvent(text: String): Event {
|
||||
return Event(
|
||||
type = "m.room.message",
|
||||
type = EventType.MESSAGE,
|
||||
eventId = "mx0",
|
||||
content = MessageTextContent("m.text", text).toContent(),
|
||||
originServerTs = 0
|
||||
originServerTs = 0,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createSimpleTextEventEncrypted(text: String): Event {
|
||||
return createFakeEncryptedEvent().apply {
|
||||
mxDecryptionResult = OlmDecryptionResult(
|
||||
payload = mapOf(
|
||||
"type" to EventType.MESSAGE,
|
||||
"content" to MessageTextContent("m.text", text).toContent(),
|
||||
),
|
||||
senderKey = "the_real_sender_key",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_eventmatch_type_condition() {
|
||||
val condition = EventMatchCondition("type", "m.room.message")
|
||||
|
@ -70,6 +99,26 @@ class PushRulesConditionTest : MatrixTest {
|
|||
assertFalse(condition.isSatisfied(simpleRoomMemberEvent))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_decrypted_eventmatch_type_condition() {
|
||||
val condition = EventMatchCondition("type", "m.room.message")
|
||||
|
||||
val simpleDecryptedTextEvent = createSimpleTextEventEncrypted("Yo wtf?")
|
||||
|
||||
val encryptedDummyEvent = createFakeEncryptedEvent().apply {
|
||||
mxDecryptionResult = OlmDecryptionResult(
|
||||
payload = mapOf(
|
||||
"type" to EventType.DUMMY,
|
||||
)
|
||||
)
|
||||
}
|
||||
val encryptedEvent = createFakeEncryptedEvent()
|
||||
|
||||
assert(condition.isSatisfied(simpleDecryptedTextEvent))
|
||||
assertFalse(condition.isSatisfied(encryptedDummyEvent))
|
||||
assertFalse(condition.isSatisfied(encryptedEvent))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_eventmatch_path_condition() {
|
||||
val condition = EventMatchCondition("content.msgtype", "m.text")
|
||||
|
@ -125,6 +174,22 @@ class PushRulesConditionTest : MatrixTest {
|
|||
assert(condition.isSatisfied(createSimpleTextEvent("BEN")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_encrypted_eventmatch_words_only_condition() {
|
||||
val condition = EventMatchCondition("content.body", "ben")
|
||||
|
||||
assertFalse(condition.isSatisfied(createSimpleTextEventEncrypted("benoit")))
|
||||
assertFalse(condition.isSatisfied(createSimpleTextEventEncrypted("Hello benoit")))
|
||||
assertFalse(condition.isSatisfied(createSimpleTextEventEncrypted("superben")))
|
||||
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("ben")))
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("hello ben")))
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("ben is there")))
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("hello ben!")))
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("hello Ben!")))
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("BEN")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_eventmatch_at_room_condition() {
|
||||
val condition = EventMatchCondition("content.body", "@room")
|
||||
|
@ -140,6 +205,21 @@ class PushRulesConditionTest : MatrixTest {
|
|||
assert(condition.isSatisfied(createSimpleTextEvent("Don't ping @room!")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_encrypted_eventmatch_at_room_condition() {
|
||||
val condition = EventMatchCondition("content.body", "@room")
|
||||
|
||||
assertFalse(condition.isSatisfied(createSimpleTextEventEncrypted("@roomba")))
|
||||
assertFalse(condition.isSatisfied(createSimpleTextEventEncrypted("room benoit")))
|
||||
assertFalse(condition.isSatisfied(createSimpleTextEventEncrypted("abc@roomba")))
|
||||
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("@room")))
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("@room, ben")))
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("@ROOM")))
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("Use:@room")))
|
||||
assert(condition.isSatisfied(createSimpleTextEventEncrypted("Don't ping @room!")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_notice_condition() {
|
||||
val conditionEqual = EventMatchCondition("content.msgtype", "m.notice")
|
||||
|
@ -155,6 +235,17 @@ class PushRulesConditionTest : MatrixTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_eventmatch_encrypted_type_condition() {
|
||||
val condition = EventMatchCondition("type", "m.room.encrypted")
|
||||
|
||||
val simpleDecryptedTextEvent = createSimpleTextEventEncrypted("Yo wtf?")
|
||||
val encryptedEvent = createFakeEncryptedEvent()
|
||||
|
||||
assertFalse(condition.isSatisfied(simpleDecryptedTextEvent))
|
||||
assert(condition.isSatisfied(encryptedEvent))
|
||||
}
|
||||
|
||||
/* ==========================================================================================
|
||||
* Test RoomMemberCountCondition
|
||||
* ========================================================================================== */
|
||||
|
|
|
@ -66,9 +66,6 @@ class NotifiableEventResolver @Inject constructor(
|
|||
private val buildMeta: BuildMeta,
|
||||
) {
|
||||
|
||||
private val nonEncryptedNotifiableEventTypes: List<String> =
|
||||
listOf(EventType.MESSAGE) + EventType.POLL_START.values + EventType.POLL_END.values + EventType.STATE_ROOM_BEACON_INFO.values
|
||||
|
||||
suspend fun resolveEvent(event: Event, session: Session, isNoisy: Boolean): NotifiableEvent? {
|
||||
val roomID = event.roomId ?: return null
|
||||
val eventId = event.eventId ?: return null
|
||||
|
@ -76,9 +73,8 @@ class NotifiableEventResolver @Inject constructor(
|
|||
return resolveStateRoomEvent(event, session, canBeReplaced = false, isNoisy = isNoisy)
|
||||
}
|
||||
val timelineEvent = session.getRoom(roomID)?.getTimelineEvent(eventId) ?: return null
|
||||
return when (event.getClearType()) {
|
||||
in nonEncryptedNotifiableEventTypes,
|
||||
EventType.ENCRYPTED -> {
|
||||
return when {
|
||||
event.supportsNotification() || event.type == EventType.ENCRYPTED -> {
|
||||
resolveMessageEvent(timelineEvent, session, canBeReplaced = false, isNoisy = isNoisy)
|
||||
}
|
||||
else -> {
|
||||
|
@ -163,8 +159,8 @@ class NotifiableEventResolver @Inject constructor(
|
|||
} else {
|
||||
event.attemptToDecryptIfNeeded(session)
|
||||
// only convert encrypted messages to NotifiableMessageEvents
|
||||
when (event.root.getClearType()) {
|
||||
in nonEncryptedNotifiableEventTypes -> {
|
||||
when {
|
||||
event.root.supportsNotification() -> {
|
||||
val body = displayableEventFormatter.format(event, isDm = room.roomSummary()?.isDirect.orFalse(), appendAuthor = false).toString()
|
||||
val roomName = room.roomSummary()?.displayName ?: ""
|
||||
val senderDisplayName = event.senderInfo.disambiguatedDisplayName
|
||||
|
|
Loading…
Reference in a new issue