-
Notifications
You must be signed in to change notification settings - Fork 754
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
Reapply push rules on the decrypted event source (PSG-1146) #8170
Conversation
Assigned to @BillCarsonFr manually, since you added the initial TODO and worked on this feature |
There was a problem hiding this 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 |
There was a problem hiding this comment.
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 type
and 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
There was a problem hiding this comment.
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).
@@ -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 |
There was a problem hiding this comment.
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, "") |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
…push_rules_after_decryption
SonarCloud Quality Gate failed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Type of change
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 forDirect Messages
orGroup Message
were enabled.Screenshots / GIFs
Tests
Tested devices
Checklist