From 7e5de9294c4d401109f6ec35d72dd3b97ad29c15 Mon Sep 17 00:00:00 2001 From: Faye Duxovni Date: Mon, 31 Jan 2022 10:49:27 -0500 Subject: [PATCH] Refine UISI autorageshake conditions to cut down on false alarms (#7650) The AutoRageshakeStore now only starts submitting rageshakes after the initial sync has completed, and provides a short grace period for decryption failures to resolve. --- src/stores/AutoRageshakeStore.ts | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/stores/AutoRageshakeStore.ts b/src/stores/AutoRageshakeStore.ts index 737c04f509..3dcd8fa119 100644 --- a/src/stores/AutoRageshakeStore.ts +++ b/src/stores/AutoRageshakeStore.ts @@ -15,6 +15,8 @@ limitations under the License. */ import { MatrixEvent } from "matrix-js-sdk/src"; +import { sleep } from "matrix-js-sdk/src/utils"; +import { ISyncStateData, SyncState } from "matrix-js-sdk/src/sync"; import SdkConfig from '../SdkConfig'; import sendBugReport from '../rageshake/submit-rageshake'; @@ -23,14 +25,17 @@ import { AsyncStoreWithClient } from './AsyncStoreWithClient'; import { ActionPayload } from '../dispatcher/payloads'; import SettingsStore from "../settings/SettingsStore"; -// Minimum interval of 5 minutes between reports, especially important when we're doing an initial sync with a lot of decryption errors -const RAGESHAKE_INTERVAL = 5*60*1000; +// Minimum interval of 1 minute between reports +const RAGESHAKE_INTERVAL = 60000; +// Before rageshaking, wait 5 seconds and see if the message has successfully decrypted +const GRACE_PERIOD = 5000; // Event type for to-device messages requesting sender auto-rageshakes const AUTO_RS_REQUEST = "im.vector.auto_rs_request"; interface IState { reportedSessionIds: Set; lastRageshakeTime: number; + initialSyncCompleted: boolean; } /** @@ -45,9 +50,11 @@ export default class AutoRageshakeStore extends AsyncStoreWithClient { super(defaultDispatcher, { reportedSessionIds: new Set(), lastRageshakeTime: 0, + initialSyncCompleted: false, }); this.onDecryptionAttempt = this.onDecryptionAttempt.bind(this); this.onDeviceMessage = this.onDeviceMessage.bind(this); + this.onSyncStateChange = this.onSyncStateChange.bind(this); } public static get instance(): AutoRageshakeStore { @@ -64,6 +71,7 @@ export default class AutoRageshakeStore extends AsyncStoreWithClient { if (this.matrixClient) { this.matrixClient.on('Event.decrypted', this.onDecryptionAttempt); this.matrixClient.on('toDeviceEvent', this.onDeviceMessage); + this.matrixClient.on('sync', this.onSyncStateChange); } } @@ -75,9 +83,14 @@ export default class AutoRageshakeStore extends AsyncStoreWithClient { } private async onDecryptionAttempt(ev: MatrixEvent): Promise { + if (!this.state.initialSyncCompleted) { return; } + const wireContent = ev.getWireContent(); const sessionId = wireContent.session_id; if (ev.isDecryptionFailure() && !this.state.reportedSessionIds.has(sessionId)) { + await sleep(GRACE_PERIOD); + if (!ev.isDecryptionFailure()) { return; } + const newReportedSessionIds = new Set(this.state.reportedSessionIds); await this.updateState({ reportedSessionIds: newReportedSessionIds.add(sessionId) }); @@ -114,6 +127,12 @@ export default class AutoRageshakeStore extends AsyncStoreWithClient { } } + private async onSyncStateChange(_state: SyncState, _prevState: SyncState, data: ISyncStateData) { + if (!this.state.initialSyncCompleted) { + await this.updateState({ initialSyncCompleted: !!data.nextSyncToken }); + } + } + private async onDeviceMessage(ev: MatrixEvent): Promise { if (ev.getType() !== AUTO_RS_REQUEST) return; const messageContent = ev.getContent();