diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 6c62000143..bcf08b26bb 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -16,6 +16,7 @@ limitations under the License. import * as ModernizrStatic from "modernizr"; import ToastStore from "../stores/ToastStore"; +import DeviceListener from "../DeviceListener"; declare global { interface Window { @@ -25,6 +26,7 @@ declare global { }; mx_ToastStore: ToastStore; + mx_DeviceListener: DeviceListener; } // workaround for https://github.com/microsoft/TypeScript/issues/30933 diff --git a/src/DeviceListener.js b/src/DeviceListener.ts similarity index 81% rename from src/DeviceListener.js rename to src/DeviceListener.ts index 27caba971e..ce1f781dad 100644 --- a/src/DeviceListener.js +++ b/src/DeviceListener.ts @@ -29,28 +29,23 @@ function toastKey(deviceId) { } export default class DeviceListener { + // device IDs for which the user has dismissed the verify toast ('Later') + private dismissed = new Set(); + // has the user dismissed any of the various nag toasts to setup encryption on this device? + private dismissedThisDeviceToast = false; + // cache of the key backup info + private keyBackupInfo: object = null; + private keyBackupFetchedAt: number = null; + // We keep a list of our own device IDs so we can batch ones that were already + // there the last time the app launched into a single toast, but display new + // ones in their own toasts. + private ourDeviceIdsAtStart: Set = null; + // The set of device IDs we're currently displaying toasts for + private displayingToastsForDeviceIds = new Set(); + static sharedInstance() { - if (!global.mx_DeviceListener) global.mx_DeviceListener = new DeviceListener(); - return global.mx_DeviceListener; - } - - constructor() { - // device IDs for which the user has dismissed the verify toast ('Later') - this._dismissed = new Set(); - // has the user dismissed any of the various nag toasts to setup encryption on this device? - this._dismissedThisDeviceToast = false; - - // cache of the key backup info - this._keyBackupInfo = null; - this._keyBackupFetchedAt = null; - - // We keep a list of our own device IDs so we can batch ones that were already - // there the last time the app launched into a single toast, but display new - // ones in their own toasts. - this._ourDeviceIdsAtStart = null; - - // The set of device IDs we're currently displaying toasts for - this._displayingToastsForDeviceIds = new Set(); + if (!window.mx_DeviceListener) window.mx_DeviceListener = new DeviceListener(); + return window.mx_DeviceListener; } start() { @@ -74,12 +69,12 @@ export default class DeviceListener { MatrixClientPeg.get().removeListener('accountData', this._onAccountData); MatrixClientPeg.get().removeListener('sync', this._onSync); } - this._dismissed.clear(); - this._dismissedThisDeviceToast = false; - this._keyBackupInfo = null; - this._keyBackupFetchedAt = null; - this._ourDeviceIdsAtStart = null; - this._displayingToastsForDeviceIds = new Set(); + this.dismissed.clear(); + this.dismissedThisDeviceToast = false; + this.keyBackupInfo = null; + this.keyBackupFetchedAt = null; + this.ourDeviceIdsAtStart = null; + this.displayingToastsForDeviceIds = new Set(); } /** @@ -87,29 +82,29 @@ export default class DeviceListener { * * @param {String[]} deviceIds List of device IDs to dismiss notifications for */ - async dismissUnverifiedSessions(deviceIds) { + async dismissUnverifiedSessions(deviceIds: string[]) { for (const d of deviceIds) { - this._dismissed.add(d); + this.dismissed.add(d); } this._recheck(); } dismissEncryptionSetup() { - this._dismissedThisDeviceToast = true; + this.dismissedThisDeviceToast = true; this._recheck(); } _ensureDeviceIdsAtStartPopulated() { - if (this._ourDeviceIdsAtStart === null) { + if (this.ourDeviceIdsAtStart === null) { const cli = MatrixClientPeg.get(); - this._ourDeviceIdsAtStart = new Set( + this.ourDeviceIdsAtStart = new Set( cli.getStoredDevicesForUser(cli.getUserId()).map(d => d.deviceId), ); } } - _onWillUpdateDevices = async (users, initialFetch) => { + _onWillUpdateDevices = async (users: string[], initialFetch?: boolean) => { // If we didn't know about *any* devices before (ie. it's fresh login), // then they are all pre-existing devices, so ignore this and set the // devicesAtStart list to the devices that we see after the fetch. @@ -122,17 +117,17 @@ export default class DeviceListener { // before we download any new ones. } - _onDevicesUpdated = (users) => { + _onDevicesUpdated = (users: string[]) => { if (!users.includes(MatrixClientPeg.get().getUserId())) return; this._recheck(); } - _onDeviceVerificationChanged = (userId) => { + _onDeviceVerificationChanged = (userId: string) => { if (userId !== MatrixClientPeg.get().getUserId()) return; this._recheck(); } - _onUserTrustStatusChanged = (userId, trustLevel) => { + _onUserTrustStatusChanged = (userId: string) => { if (userId !== MatrixClientPeg.get().getUserId()) return; this._recheck(); } @@ -163,11 +158,11 @@ export default class DeviceListener { // & cache the result async _getKeyBackupInfo() { const now = (new Date()).getTime(); - if (!this._keyBackupInfo || this._keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) { - this._keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); - this._keyBackupFetchedAt = now; + if (!this.keyBackupInfo || this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) { + this.keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); + this.keyBackupFetchedAt = now; } - return this._keyBackupInfo; + return this.keyBackupInfo; } async _recheck() { @@ -186,7 +181,7 @@ export default class DeviceListener { const crossSigningReady = await cli.isCrossSigningReady(); - if (this._dismissedThisDeviceToast) { + if (this.dismissedThisDeviceToast) { ToastStore.sharedInstance().dismissToast(THIS_DEVICE_TOAST_KEY); } else { if (!crossSigningReady) { @@ -239,20 +234,20 @@ export default class DeviceListener { // (technically could just be a boolean: we don't actually // need to remember the device IDs, but for the sake of // symmetry...). - const oldUnverifiedDeviceIds = new Set(); + const oldUnverifiedDeviceIds = new Set(); // Unverified devices that have appeared since then - const newUnverifiedDeviceIds = new Set(); + const newUnverifiedDeviceIds = new Set(); // as long as cross-signing isn't ready, // you can't see or dismiss any device toasts if (crossSigningReady) { const devices = cli.getStoredDevicesForUser(cli.getUserId()); for (const device of devices) { - if (device.deviceId == cli.deviceId) continue; + if (device.deviceId === cli.deviceId) continue; const deviceTrust = await cli.checkDeviceTrust(cli.getUserId(), device.deviceId); - if (!deviceTrust.isCrossSigningVerified() && !this._dismissed.has(device.deviceId)) { - if (this._ourDeviceIdsAtStart.has(device.deviceId)) { + if (!deviceTrust.isCrossSigningVerified() && !this.dismissed.has(device.deviceId)) { + if (this.ourDeviceIdsAtStart.has(device.deviceId)) { oldUnverifiedDeviceIds.add(device.deviceId); } else { newUnverifiedDeviceIds.add(device.deviceId); @@ -289,12 +284,12 @@ export default class DeviceListener { } // ...and hide any we don't need any more - for (const deviceId of this._displayingToastsForDeviceIds) { + for (const deviceId of this.displayingToastsForDeviceIds) { if (!newUnverifiedDeviceIds.has(deviceId)) { ToastStore.sharedInstance().dismissToast(toastKey(deviceId)); } } - this._displayingToastsForDeviceIds = newUnverifiedDeviceIds; + this.displayingToastsForDeviceIds = newUnverifiedDeviceIds; } }