@@ -17,11 +17,10 @@ limitations under the License.
17
17
import { MatrixEvent } from "matrix-js-sdk/src/models/event" ;
18
18
import { logger } from "matrix-js-sdk/src/logger" ;
19
19
import { CryptoEvent } from "matrix-js-sdk/src/crypto" ;
20
- import { ClientEvent , EventType , RoomStateEvent } from "matrix-js-sdk/src/matrix" ;
20
+ import { ClientEvent , EventType , MatrixClient , RoomStateEvent } from "matrix-js-sdk/src/matrix" ;
21
21
import { SyncState } from "matrix-js-sdk/src/sync" ;
22
22
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup" ;
23
23
24
- import { MatrixClientPeg } from "./MatrixClientPeg" ;
25
24
import dis from "./dispatcher/dispatcher" ;
26
25
import {
27
26
hideToast as hideBulkUnverifiedSessionsToast ,
@@ -67,6 +66,8 @@ export default class DeviceListener {
67
66
// The set of device IDs we're currently displaying toasts for
68
67
private displayingToastsForDeviceIds = new Set < string > ( ) ;
69
68
private running = false ;
69
+ // The client with which the instance is running. Only set if `running` is true, otherwise undefined.
70
+ private client ?: MatrixClient ;
70
71
private shouldRecordClientInformation = false ;
71
72
private enableBulkUnverifiedSessionsReminder = true ;
72
73
private deviceClientInformationSettingWatcherRef : string | undefined ;
@@ -76,16 +77,17 @@ export default class DeviceListener {
76
77
return window . mxDeviceListener ;
77
78
}
78
79
79
- public start ( ) : void {
80
+ public start ( matrixClient : MatrixClient ) : void {
80
81
this . running = true ;
81
- MatrixClientPeg . get ( ) . on ( CryptoEvent . WillUpdateDevices , this . onWillUpdateDevices ) ;
82
- MatrixClientPeg . get ( ) . on ( CryptoEvent . DevicesUpdated , this . onDevicesUpdated ) ;
83
- MatrixClientPeg . get ( ) . on ( CryptoEvent . DeviceVerificationChanged , this . onDeviceVerificationChanged ) ;
84
- MatrixClientPeg . get ( ) . on ( CryptoEvent . UserTrustStatusChanged , this . onUserTrustStatusChanged ) ;
85
- MatrixClientPeg . get ( ) . on ( CryptoEvent . KeysChanged , this . onCrossSingingKeysChanged ) ;
86
- MatrixClientPeg . get ( ) . on ( ClientEvent . AccountData , this . onAccountData ) ;
87
- MatrixClientPeg . get ( ) . on ( ClientEvent . Sync , this . onSync ) ;
88
- MatrixClientPeg . get ( ) . on ( RoomStateEvent . Events , this . onRoomStateEvents ) ;
82
+ this . client = matrixClient ;
83
+ this . client . on ( CryptoEvent . WillUpdateDevices , this . onWillUpdateDevices ) ;
84
+ this . client . on ( CryptoEvent . DevicesUpdated , this . onDevicesUpdated ) ;
85
+ this . client . on ( CryptoEvent . DeviceVerificationChanged , this . onDeviceVerificationChanged ) ;
86
+ this . client . on ( CryptoEvent . UserTrustStatusChanged , this . onUserTrustStatusChanged ) ;
87
+ this . client . on ( CryptoEvent . KeysChanged , this . onCrossSingingKeysChanged ) ;
88
+ this . client . on ( ClientEvent . AccountData , this . onAccountData ) ;
89
+ this . client . on ( ClientEvent . Sync , this . onSync ) ;
90
+ this . client . on ( RoomStateEvent . Events , this . onRoomStateEvents ) ;
89
91
this . shouldRecordClientInformation = SettingsStore . getValue ( "deviceClientInformationOptIn" ) ;
90
92
// only configurable in config, so we don't need to watch the value
91
93
this . enableBulkUnverifiedSessionsReminder = SettingsStore . getValue ( UIFeature . BulkUnverifiedSessionsReminder ) ;
@@ -101,18 +103,15 @@ export default class DeviceListener {
101
103
102
104
public stop ( ) : void {
103
105
this . running = false ;
104
- if ( MatrixClientPeg . get ( ) ) {
105
- MatrixClientPeg . get ( ) . removeListener ( CryptoEvent . WillUpdateDevices , this . onWillUpdateDevices ) ;
106
- MatrixClientPeg . get ( ) . removeListener ( CryptoEvent . DevicesUpdated , this . onDevicesUpdated ) ;
107
- MatrixClientPeg . get ( ) . removeListener (
108
- CryptoEvent . DeviceVerificationChanged ,
109
- this . onDeviceVerificationChanged ,
110
- ) ;
111
- MatrixClientPeg . get ( ) . removeListener ( CryptoEvent . UserTrustStatusChanged , this . onUserTrustStatusChanged ) ;
112
- MatrixClientPeg . get ( ) . removeListener ( CryptoEvent . KeysChanged , this . onCrossSingingKeysChanged ) ;
113
- MatrixClientPeg . get ( ) . removeListener ( ClientEvent . AccountData , this . onAccountData ) ;
114
- MatrixClientPeg . get ( ) . removeListener ( ClientEvent . Sync , this . onSync ) ;
115
- MatrixClientPeg . get ( ) . removeListener ( RoomStateEvent . Events , this . onRoomStateEvents ) ;
106
+ if ( this . client ) {
107
+ this . client . removeListener ( CryptoEvent . WillUpdateDevices , this . onWillUpdateDevices ) ;
108
+ this . client . removeListener ( CryptoEvent . DevicesUpdated , this . onDevicesUpdated ) ;
109
+ this . client . removeListener ( CryptoEvent . DeviceVerificationChanged , this . onDeviceVerificationChanged ) ;
110
+ this . client . removeListener ( CryptoEvent . UserTrustStatusChanged , this . onUserTrustStatusChanged ) ;
111
+ this . client . removeListener ( CryptoEvent . KeysChanged , this . onCrossSingingKeysChanged ) ;
112
+ this . client . removeListener ( ClientEvent . AccountData , this . onAccountData ) ;
113
+ this . client . removeListener ( ClientEvent . Sync , this . onSync ) ;
114
+ this . client . removeListener ( RoomStateEvent . Events , this . onRoomStateEvents ) ;
116
115
}
117
116
if ( this . deviceClientInformationSettingWatcherRef ) {
118
117
SettingsStore . unwatchSetting ( this . deviceClientInformationSettingWatcherRef ) ;
@@ -128,6 +127,7 @@ export default class DeviceListener {
128
127
this . keyBackupStatusChecked = false ;
129
128
this . ourDeviceIdsAtStart = null ;
130
129
this . displayingToastsForDeviceIds = new Set ( ) ;
130
+ this . client = undefined ;
131
131
}
132
132
133
133
/**
@@ -160,40 +160,44 @@ export default class DeviceListener {
160
160
* @returns the set of device IDs
161
161
*/
162
162
private async getDeviceIds ( ) : Promise < Set < string > > {
163
- const cli = MatrixClientPeg . get ( ) ;
164
- const crypto = cli . getCrypto ( ) ;
163
+ const cli = this . client ;
164
+ const crypto = cli ? .getCrypto ( ) ;
165
165
if ( crypto === undefined ) return new Set ( ) ;
166
166
167
- const userId = cli . getSafeUserId ( ) ;
167
+ const userId = cli ! . getSafeUserId ( ) ;
168
168
const devices = await crypto . getUserDeviceInfo ( [ userId ] ) ;
169
169
return new Set ( devices . get ( userId ) ?. keys ( ) ?? [ ] ) ;
170
170
}
171
171
172
172
private onWillUpdateDevices = async ( users : string [ ] , initialFetch ?: boolean ) : Promise < void > => {
173
+ if ( ! this . client ) return ;
173
174
// If we didn't know about *any* devices before (ie. it's fresh login),
174
175
// then they are all pre-existing devices, so ignore this and set the
175
176
// devicesAtStart list to the devices that we see after the fetch.
176
177
if ( initialFetch ) return ;
177
178
178
- const myUserId = MatrixClientPeg . get ( ) . getUserId ( ) ! ;
179
+ const myUserId = this . client . getSafeUserId ( ) ;
179
180
if ( users . includes ( myUserId ) ) await this . ensureDeviceIdsAtStartPopulated ( ) ;
180
181
181
182
// No need to do a recheck here: we just need to get a snapshot of our devices
182
183
// before we download any new ones.
183
184
} ;
184
185
185
186
private onDevicesUpdated = ( users : string [ ] ) : void => {
186
- if ( ! users . includes ( MatrixClientPeg . get ( ) . getUserId ( ) ! ) ) return ;
187
+ if ( ! this . client ) return ;
188
+ if ( ! users . includes ( this . client . getSafeUserId ( ) ) ) return ;
187
189
this . recheck ( ) ;
188
190
} ;
189
191
190
192
private onDeviceVerificationChanged = ( userId : string ) : void => {
191
- if ( userId !== MatrixClientPeg . get ( ) . getUserId ( ) ) return ;
193
+ if ( ! this . client ) return ;
194
+ if ( userId !== this . client . getUserId ( ) ) return ;
192
195
this . recheck ( ) ;
193
196
} ;
194
197
195
198
private onUserTrustStatusChanged = ( userId : string ) : void => {
196
- if ( userId !== MatrixClientPeg . get ( ) . getUserId ( ) ) return ;
199
+ if ( ! this . client ) return ;
200
+ if ( userId !== this . client . getUserId ( ) ) return ;
197
201
this . recheck ( ) ;
198
202
} ;
199
203
@@ -239,13 +243,14 @@ export default class DeviceListener {
239
243
// The server doesn't tell us when key backup is set up, so we poll
240
244
// & cache the result
241
245
private async getKeyBackupInfo ( ) : Promise < IKeyBackupInfo | null > {
246
+ if ( ! this . client ) return null ;
242
247
const now = new Date ( ) . getTime ( ) ;
243
248
if (
244
249
! this . keyBackupInfo ||
245
250
! this . keyBackupFetchedAt ||
246
251
this . keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL
247
252
) {
248
- this . keyBackupInfo = await MatrixClientPeg . get ( ) . getKeyBackupVersion ( ) ;
253
+ this . keyBackupInfo = await this . client . getKeyBackupVersion ( ) ;
249
254
this . keyBackupFetchedAt = now ;
250
255
}
251
256
return this . keyBackupInfo ;
@@ -256,13 +261,13 @@ export default class DeviceListener {
256
261
// modifying the state involved here, so don't add new toasts to setup.
257
262
if ( isSecretStorageBeingAccessed ( ) ) return false ;
258
263
// Show setup toasts once the user is in at least one encrypted room.
259
- const cli = MatrixClientPeg . get ( ) ;
260
- return cli && cli . getRooms ( ) . some ( ( r ) => cli . isRoomEncrypted ( r . roomId ) ) ;
264
+ const cli = this . client ;
265
+ return cli ? .getRooms ( ) . some ( ( r ) => cli . isRoomEncrypted ( r . roomId ) ) ?? false ;
261
266
}
262
267
263
268
private async recheck ( ) : Promise < void > {
264
- if ( ! this . running ) return ; // we have been stopped
265
- const cli = MatrixClientPeg . get ( ) ;
269
+ if ( ! this . running || ! this . client ) return ; // we have been stopped
270
+ const cli = this . client ;
266
271
267
272
// cross-signing support was added to Matrix in MSC1756, which landed in spec v1.1
268
273
if ( ! ( await cli . isVersionSupported ( "v1.1" ) ) ) return ;
@@ -285,11 +290,11 @@ export default class DeviceListener {
285
290
this . checkKeyBackupStatus ( ) ;
286
291
} else if ( this . shouldShowSetupEncryptionToast ( ) ) {
287
292
// make sure our keys are finished downloading
288
- await crypto . getUserDeviceInfo ( [ cli . getUserId ( ) ! ] ) ;
293
+ await crypto . getUserDeviceInfo ( [ cli . getSafeUserId ( ) ] ) ;
289
294
290
295
// cross signing isn't enabled - nag to enable it
291
296
// There are 3 different toasts for:
292
- if ( ! ( await crypto . getCrossSigningKeyId ( ) ) && cli . getStoredCrossSigningForUser ( cli . getUserId ( ) ! ) ) {
297
+ if ( ! ( await crypto . getCrossSigningKeyId ( ) ) && cli . getStoredCrossSigningForUser ( cli . getSafeUserId ( ) ) ) {
293
298
// Cross-signing on account but this device doesn't trust the master key (verify this session)
294
299
showSetupEncryptionToast ( SetupKind . VERIFY_THIS_SESSION ) ;
295
300
this . checkKeyBackupStatus ( ) ;
@@ -327,7 +332,9 @@ export default class DeviceListener {
327
332
328
333
const isCurrentDeviceTrusted =
329
334
crossSigningReady &&
330
- Boolean ( ( await crypto . getDeviceVerificationStatus ( cli . getUserId ( ) ! , cli . deviceId ! ) ) ?. crossSigningVerified ) ;
335
+ Boolean (
336
+ ( await crypto . getDeviceVerificationStatus ( cli . getSafeUserId ( ) , cli . deviceId ! ) ) ?. crossSigningVerified ,
337
+ ) ;
331
338
332
339
// as long as cross-signing isn't ready,
333
340
// you can't see or dismiss any device toasts
@@ -336,7 +343,7 @@ export default class DeviceListener {
336
343
for ( const deviceId of devices ) {
337
344
if ( deviceId === cli . deviceId ) continue ;
338
345
339
- const deviceTrust = await crypto . getDeviceVerificationStatus ( cli . getUserId ( ) ! , deviceId ) ;
346
+ const deviceTrust = await crypto . getDeviceVerificationStatus ( cli . getSafeUserId ( ) , deviceId ) ;
340
347
if ( ! deviceTrust ?. crossSigningVerified && ! this . dismissed . has ( deviceId ) ) {
341
348
if ( this . ourDeviceIdsAtStart ?. has ( deviceId ) ) {
342
349
oldUnverifiedDeviceIds . add ( deviceId ) ;
@@ -383,11 +390,11 @@ export default class DeviceListener {
383
390
}
384
391
385
392
private checkKeyBackupStatus = async ( ) : Promise < void > => {
386
- if ( this . keyBackupStatusChecked ) {
393
+ if ( this . keyBackupStatusChecked || ! this . client ) {
387
394
return ;
388
395
}
389
396
// returns null when key backup status hasn't finished being checked
390
- const isKeyBackupEnabled = MatrixClientPeg . get ( ) . getKeyBackupEnabled ( ) ;
397
+ const isKeyBackupEnabled = this . client . getKeyBackupEnabled ( ) ;
391
398
this . keyBackupStatusChecked = isKeyBackupEnabled !== null ;
392
399
393
400
if ( isKeyBackupEnabled === false ) {
@@ -412,11 +419,12 @@ export default class DeviceListener {
412
419
} ;
413
420
414
421
private updateClientInformation = async ( ) : Promise < void > => {
422
+ if ( ! this . client ) return ;
415
423
try {
416
424
if ( this . shouldRecordClientInformation ) {
417
- await recordClientInformation ( MatrixClientPeg . get ( ) , SdkConfig . get ( ) , PlatformPeg . get ( ) ?? undefined ) ;
425
+ await recordClientInformation ( this . client , SdkConfig . get ( ) , PlatformPeg . get ( ) ?? undefined ) ;
418
426
} else {
419
- await removeClientInformation ( MatrixClientPeg . get ( ) ) ;
427
+ await removeClientInformation ( this . client ) ;
420
428
}
421
429
} catch ( error ) {
422
430
// this is a best effort operation
0 commit comments