Only report undecryptable events once (#12501)

* persist previously-reported event IDs as a bloom filter

* Pin to older `@types/seedrandom`

... to work around https://github.com/Callidon/bloom-filters/issues/72

* Inline `DecryptionFailureTracker.addDecryptionFailure`

* Remove redundant TRACK_INTERVAL

There really doesn't seem to be much point to this batching up of decryption
failure reports. We still call the analytics callback the same number of times.

* Rename `trackedEvents` to `reportedEvents`

* Fix incorrect documentation on `visibleEvents`

This *does* overlap with `failures`.

* Combine `addFailure` and `reportFailure`

* Calculate client properties before starting reporting

* Clear localstorage after each test

... otherwise they interfere

* Remove redundant comment

* Ensure that reports are cleared on a logout/login cycle

* make private const private and const

---------

Co-authored-by: Richard van der Hoff <richard@matrix.org>
This commit is contained in:
Hubert Chathi 2024-05-20 10:53:50 -04:00 committed by GitHub
parent 3e103941d6
commit 1bb70c5b3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 197 additions and 73 deletions

View file

@ -14,12 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { ScalableBloomFilter } from "bloom-filters";
import { CryptoEvent, HttpApiEvent, MatrixClient, MatrixEventEvent, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { Error as ErrorEvent } from "@matrix-org/analytics-events/types/typescript/Error";
import { DecryptionFailureCode } from "matrix-js-sdk/src/crypto-api";
import { PosthogAnalytics } from "./PosthogAnalytics";
/** The key that we use to store the `reportedEvents` bloom filter in localstorage */
const DECRYPTION_FAILURE_STORAGE_KEY = "mx_decryption_failure_event_ids";
export class DecryptionFailure {
/**
* The time between our initial failure to decrypt and our successful
@ -104,8 +108,8 @@ export class DecryptionFailureTracker {
*/
public visibleEvents: Set<string> = new Set();
/** Event IDs of failures that were reported previously */
private reportedEvents: Set<string> = new Set();
/** Bloom filter tracking event IDs of failures that were reported previously */
private reportedEvents: ScalableBloomFilter = new ScalableBloomFilter();
/** Set to an interval ID when `start` is called */
public checkInterval: number | null = null;
@ -172,13 +176,18 @@ export class DecryptionFailureTracker {
return DecryptionFailureTracker.internalInstance;
}
// loadReportedEvents() {
// this.reportedEvents = new Set(JSON.parse(localStorage.getItem('mx-decryption-failure-event-ids')) || []);
// }
private loadReportedEvents(): void {
const storedFailures = localStorage.getItem(DECRYPTION_FAILURE_STORAGE_KEY);
if (storedFailures) {
this.reportedEvents = ScalableBloomFilter.fromJSON(JSON.parse(storedFailures));
} else {
this.reportedEvents = new ScalableBloomFilter();
}
}
// saveReportedEvents() {
// localStorage.setItem('mx-decryption-failure-event-ids', JSON.stringify([...this.reportedEvents]));
// }
private saveReportedEvents(): void {
localStorage.setItem(DECRYPTION_FAILURE_STORAGE_KEY, JSON.stringify(this.reportedEvents.saveAsJSON()));
}
/** Callback for when an event is decrypted.
*
@ -290,6 +299,7 @@ export class DecryptionFailureTracker {
* Start checking for and tracking failures.
*/
public async start(client: MatrixClient): Promise<void> {
this.loadReportedEvents();
await this.calculateClientProperties(client);
this.registerHandlers(client);
this.checkInterval = window.setInterval(
@ -385,9 +395,7 @@ export class DecryptionFailureTracker {
}
this.failures = failuresNotReady;
// Commented out for now for expediency, we need to consider unbound nature of storing
// this in localStorage
// this.saveReportedEvents();
this.saveReportedEvents();
}
/**