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:
parent
3e103941d6
commit
1bb70c5b3b
5 changed files with 197 additions and 73 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,8 +23,8 @@ import {
|
|||
MatrixClient,
|
||||
MatrixEvent,
|
||||
RoomType,
|
||||
SyncStateData,
|
||||
SyncState,
|
||||
SyncStateData,
|
||||
TimelineEvents,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { defer, IDeferred, QueryDict } from "matrix-js-sdk/src/utils";
|
||||
|
@ -128,7 +128,7 @@ import { TimelineRenderingType } from "../../contexts/RoomContext";
|
|||
import { UseCaseSelection } from "../views/elements/UseCaseSelection";
|
||||
import { ValidatedServerConfig } from "../../utils/ValidatedServerConfig";
|
||||
import { isLocalRoom } from "../../utils/localRoom/isLocalRoom";
|
||||
import { SdkContextClass, SDKContext } from "../../contexts/SDKContext";
|
||||
import { SDKContext, SdkContextClass } from "../../contexts/SDKContext";
|
||||
import { viewUserDeviceSettings } from "../../actions/handlers/viewUserDeviceSettings";
|
||||
import { cleanUpBroadcasts, VoiceBroadcastResumer } from "../../voice-broadcast";
|
||||
import GenericToast from "../views/toasts/GenericToast";
|
||||
|
@ -1585,13 +1585,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
);
|
||||
});
|
||||
|
||||
const dft = DecryptionFailureTracker.instance;
|
||||
|
||||
// Shelved for later date when we have time to think about persisting history of
|
||||
// tracked events across sessions.
|
||||
// dft.loadTrackedEventHashMap();
|
||||
|
||||
dft.start(cli).catch((e) => logger.error("Unable to start DecryptionFailureTracker", e));
|
||||
DecryptionFailureTracker.instance
|
||||
.start(cli)
|
||||
.catch((e) => logger.error("Unable to start DecryptionFailureTracker", e));
|
||||
|
||||
cli.on(ClientEvent.Room, (room) => {
|
||||
if (cli.isCryptoEnabled()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue