Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reapply push rules on the decrypted event source (PSG-1146) #8170

Merged
merged 10 commits into from
Mar 7, 2023

Conversation

Florian14
Copy link
Contributor

Type of change

  • Feature
  • Bugfix
  • Technical
  • Other :

Content

Reapply the local push rules on the decrypted event content.

Motivation and context

When the notifications were enabled for encrypted events, we did not reapply the push rules on the decrypted content, so all the encrypted events were triggering a notification even if the notifications for Direct Messages or Group Message were enabled.

Screenshots / GIFs

Tests

  • Enable all the default notifications from the app settings (DM, Group Messages, encrypted DM, encrypted Group Messages)
  • Put the app in bg
  • Send a message in encrypted DM & encrypted room (> 2 members) from another account
  • Verify that you receive both notifications
  • Disable DM, go in bg & send a message from the other account in both rooms
  • Verify there is a single notification for group messages
  • Enable DM & disable encrypted DM
  • Test again and verify that you have the same result
  • Do the same tests for group messages (you should only receive notifications in DM)

Tested devices

  • Physical
  • Emulator
  • OS version(s):

Checklist

@Florian14
Copy link
Contributor Author

Assigned to @BillCarsonFr manually, since you added the initial TODO and worked on this feature

@Florian14 Florian14 changed the title Reapply push rules on the decrypted event source Reapply push rules on the decrypted event source (PSG-1146) Feb 24, 2023
Copy link
Member

@BillCarsonFr BillCarsonFr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is an issue with that code

@@ -39,8 +39,8 @@ 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<*, *> = event.mxDecryptionResult?.payload
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't looks correct to me. The key "path" is based on the full event content.
If you only take the payload it won't work as expected.
Eg the key content.body won't work because your raw json will be

{ "body": "xxxx" }

Instead of

{ "content" : {{ "body": "xxxx" }} "

What you would need to do is to take the rawJson, then in case of encrypted event (with a decryption result) you replace the typeand content with what is in event.mxDecryptionResult.

There is an existing test class for this condition you can add test to check that it's working as expected

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated with your suggestion, I replace all the entries from the encrypted raw json with the decrypted one. Also, I had to ensure the event is decrypted before applying the push rules. It was not necessary when I tested last time but it seems that the event is not always decrypted at this moment (it was not the case currently).

@Florian14 Florian14 requested a review from BillCarsonFr March 1, 2023 10:50
@@ -94,6 +94,7 @@ 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) {
if (event.type == EventType.ENCRYPTED && event.mxDecryptionResult != null) return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually to detect failed to decrypt we do getClearType() == m.room.encrypted

@@ -73,6 +75,7 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
" to check for push rules with ${params.rules.size} rules"
)
val matchedEvents = allEvents.mapNotNull { event ->
eventDecryptor.decryptEventAndSaveResult(event, "")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might do unnecessary redecryption. Should be a decrypt if needed (test if amready decrypted before retrying).
Also at this point if it's not decrypted, I don't think that the second attempt will work. We don't have the key.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decryptEventAndSaveResult just returns if the event is already decrypted.
I just tested again with some logs and I confirm that the event is successfully decrypted at this moment:

13:03:51.024  V  [PushRules] --> checkPushRules
13:03:51.043  V  Execute transaction in 20 millis
13:03:51.063  V  [PushRules] Found 1 out of 1 to check for push rules with 27 rules
13:03:51.064  D  decryptEventAndSaveResult | event.getClearType()=m.room.encrypted
13:03:51.065  V  decryptEvent $i8Dx2Ri7FIr-meu********, requestKeysOnFail:true
13:03:51.065  V  ## Inbound: getInboundGroupSession  2Ge4kbC0P******** in cache true
13:03:51.069  V  ##########################################################
13:03:51.070  V  ## decryptGroupMessage() timeline: 
13:03:51.070  V  ## decryptGroupMessage() senderKey: AvjFBpOE************
13:03:51.071  V  ## decryptGroupMessage() sessionId: 2Ge4k***************
13:03:51.071  V  ## decryptGroupMessage() roomId: !fngDRO********
13:03:51.072  V  ## decryptGroupMessage() eventId: $i8Dx2Ri7FIr-meu********
13:03:51.072  V  ## decryptGroupMessage() mIndex: 17
13:03:51.073  V  ## dispatchLiveEventDecrypted $i8Dx2Ri7FIr-meu******
13:03:51.075  D  decryptEventAndSaveResult | update event with decryption result: MXEventDecryptionResult(clearEvent={room_id=!fngDRO******, type=m.room.message, content={msgtype=m.text, body=test event in encrypted room}}, senderCurve25519Key=AvjFBpOEsqVexQ9F********, claimedEd25519Key=R5fd2pJs9XH******, forwardingCurve25519KeyChain=[], isSafe=true)
13:03:51.105  D  Skipping notification update due to event list not changing
13:03:51.139  V  [PushRules] Rule PushRule(actions=[notify, {set_tweak=sound, value=default}], default=false, enabled=true, ruleId=.m.rule.message, conditions=[PushCondition(kind=event_match, key=type, pattern=m.room.message, iz=null)], pattern=null) match for event $i8Dx2Ri7FIr-meu*******
13:03:51.140  D  [PushRules] matched 1 out of 1
13:03:51.141  V  [PushRules] Found 0 redacted events
13:03:51.143  D  Push rule match for event $i8Dx2Ri7FIr-meu******
13:03:51.148  V  [PushRules] <-- Push task scheduled

I agree that this is probably not the best place to try to decrypt but it seems relevant to do the decryption. But I don't really know where it'd be better to do the decryption tbh

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I see the problem.
In DefaultProcessEventForPushTask there is that:

it.takeIf { ... }?.copy(roomId = key)

This is doing a copy to add the roomId to the event, but the normal copy is not copying @Transiant fields. So it removed the decryption result.

So I think it should use copyAll()instead.

@@ -155,6 +172,33 @@ class PushRulesConditionTest : MatrixTest {
}
}

@Test
fun test_decrypted_eventmatch_type_condition() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add some test for content match rules:

  • m.rules.contains_user_name: content.body matches "alice"
  • m.rules.roomnotif: content.body matches "@room"

And an additional test to proove that a decrypted event won't match anymore the .m.rule.encrypted(type matches "m.room.encrypted")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Florian14 Florian14 requested a review from BillCarsonFr March 1, 2023 12:53
Florian Renaud added 3 commits March 2, 2023 14:40
As the decryption is done on a copy of the event (containing the roomId), we have to update the initial event with the decryption result
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 6, 2023

SonarCloud Quality Gate failed.    Quality Gate failed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

34.7% 34.7% Coverage
0.0% 0.0% Duplication

Copy link
Member

@BillCarsonFr BillCarsonFr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Florian14 Florian14 merged commit 39c702f into develop Mar 7, 2023
@Florian14 Florian14 deleted the feature/fre/apply_push_rules_after_decryption branch March 7, 2023 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants