@@ -97,6 +97,7 @@ export default class DeviceListener {
97
97
this . client . on ( CryptoEvent . DevicesUpdated , this . onDevicesUpdated ) ;
98
98
this . client . on ( CryptoEvent . UserTrustStatusChanged , this . onUserTrustStatusChanged ) ;
99
99
this . client . on ( CryptoEvent . KeysChanged , this . onCrossSingingKeysChanged ) ;
100
+ this . client . on ( CryptoEvent . KeyBackupStatus , this . onKeyBackupStatusChanged ) ;
100
101
this . client . on ( ClientEvent . AccountData , this . onAccountData ) ;
101
102
this . client . on ( ClientEvent . Sync , this . onSync ) ;
102
103
this . client . on ( RoomStateEvent . Events , this . onRoomStateEvents ) ;
@@ -132,7 +133,7 @@ export default class DeviceListener {
132
133
this . dismissedThisDeviceToast = false ;
133
134
this . keyBackupInfo = null ;
134
135
this . keyBackupFetchedAt = null ;
135
- this . cachedKeyBackupStatus = undefined ;
136
+ this . cachedKeyBackupUploadActive = undefined ;
136
137
this . ourDeviceIdsAtStart = null ;
137
138
this . displayingToastsForDeviceIds = new Set ( ) ;
138
139
this . client = undefined ;
@@ -157,6 +158,13 @@ export default class DeviceListener {
157
158
this . recheck ( ) ;
158
159
}
159
160
161
+ /**
162
+ * Set the account data "m.org.matrix.custom.backup_disabled" to { "disabled": true }.
163
+ */
164
+ public async recordKeyBackupDisabled ( ) : Promise < void > {
165
+ await this . client ?. setAccountData ( BACKUP_DISABLED_ACCOUNT_DATA_KEY , { disabled : true } ) ;
166
+ }
167
+
160
168
private async ensureDeviceIdsAtStartPopulated ( ) : Promise < void > {
161
169
if ( this . ourDeviceIdsAtStart === null ) {
162
170
this . ourDeviceIdsAtStart = await this . getDeviceIds ( ) ;
@@ -192,6 +200,11 @@ export default class DeviceListener {
192
200
this . recheck ( ) ;
193
201
} ;
194
202
203
+ private onKeyBackupStatusChanged = ( ) : void => {
204
+ this . cachedKeyBackupUploadActive = undefined ;
205
+ this . recheck ( ) ;
206
+ } ;
207
+
195
208
private onCrossSingingKeysChanged = ( ) : void => {
196
209
this . recheck ( ) ;
197
210
} ;
@@ -201,11 +214,13 @@ export default class DeviceListener {
201
214
// * migrated SSSS to symmetric
202
215
// * uploaded keys to secret storage
203
216
// * completed secret storage creation
217
+ // * disabled key backup
204
218
// which result in account data changes affecting checks below.
205
219
if (
206
220
ev . getType ( ) . startsWith ( "m.secret_storage." ) ||
207
221
ev . getType ( ) . startsWith ( "m.cross_signing." ) ||
208
- ev . getType ( ) === "m.megolm_backup.v1"
222
+ ev . getType ( ) === "m.megolm_backup.v1" ||
223
+ ev . getType ( ) === BACKUP_DISABLED_ACCOUNT_DATA_KEY
209
224
) {
210
225
this . recheck ( ) ;
211
226
}
@@ -324,7 +339,16 @@ export default class DeviceListener {
324
339
( await crypto . getDeviceVerificationStatus ( cli . getSafeUserId ( ) , cli . deviceId ! ) ) ?. crossSigningVerified ,
325
340
) ;
326
341
327
- const allSystemsReady = crossSigningReady && secretStorageReady && allCrossSigningSecretsCached ;
342
+ const keyBackupUploadActive = await this . isKeyBackupUploadActive ( ) ;
343
+ const backupDisabled = await this . recheckBackupDisabled ( cli ) ;
344
+
345
+ // We warn if key backup upload is turned off and we have not explicitly
346
+ // said we are OK with that.
347
+ const keyBackupIsOk = keyBackupUploadActive || backupDisabled ;
348
+
349
+ const allSystemsReady =
350
+ crossSigningReady && keyBackupIsOk && secretStorageReady && allCrossSigningSecretsCached ;
351
+
328
352
await this . reportCryptoSessionStateToAnalytics ( cli ) ;
329
353
330
354
if ( this . dismissedThisDeviceToast || allSystemsReady ) {
@@ -353,14 +377,19 @@ export default class DeviceListener {
353
377
crossSigningStatus . privateKeysCachedLocally ,
354
378
) ;
355
379
showSetupEncryptionToast ( SetupKind . KEY_STORAGE_OUT_OF_SYNC ) ;
380
+ } else if ( ! keyBackupIsOk ) {
381
+ logSpan . info ( "Key backup upload is unexpectedly turned off: showing TURN_ON_KEY_STORAGE toast" ) ;
382
+ showSetupEncryptionToast ( SetupKind . TURN_ON_KEY_STORAGE ) ;
356
383
} else if ( defaultKeyId === null ) {
357
- // the user just hasn't set up 4S yet: prompt them to do so (unless they've explicitly said no to key storage)
358
- const disabledEvent = cli . getAccountData ( BACKUP_DISABLED_ACCOUNT_DATA_KEY ) ;
359
- if ( ! disabledEvent ?. getContent ( ) . disabled ) {
384
+ // The user just hasn't set up 4S yet: if they have key
385
+ // backup, prompt them to turn on recovery too. (If not, they
386
+ // have explicitly opted out, so don't hassle them.)
387
+ if ( keyBackupUploadActive ) {
360
388
logSpan . info ( "No default 4S key: showing SET_UP_RECOVERY toast" ) ;
361
389
showSetupEncryptionToast ( SetupKind . SET_UP_RECOVERY ) ;
362
390
} else {
363
391
logSpan . info ( "No default 4S key but backup disabled: no toast needed" ) ;
392
+ hideSetupEncryptionToast ( ) ;
364
393
}
365
394
} else {
366
395
// some other condition... yikes! Show the 'set up encryption' toast: this is what we previously did
@@ -443,6 +472,16 @@ export default class DeviceListener {
443
472
this . displayingToastsForDeviceIds = newUnverifiedDeviceIds ;
444
473
}
445
474
475
+ /**
476
+ * Fetch the account data for `backup_disabled`. If this is the first time,
477
+ * fetch it from the server (in case the initial sync has not finished).
478
+ * Otherwise, fetch it from the store as normal.
479
+ */
480
+ private async recheckBackupDisabled ( cli : MatrixClient ) : Promise < boolean > {
481
+ const backupDisabled = await cli . getAccountDataFromServer ( BACKUP_DISABLED_ACCOUNT_DATA_KEY ) ;
482
+ return ! ! backupDisabled ?. disabled ;
483
+ }
484
+
446
485
/**
447
486
* Reports current recovery state to analytics.
448
487
* Checks if the session is verified and if the recovery is correctly set up (i.e all secrets known locally and in 4S).
@@ -512,36 +551,42 @@ export default class DeviceListener {
512
551
* trigger an auto-rageshake).
513
552
*/
514
553
private checkKeyBackupStatus = async ( ) : Promise < void > => {
515
- if ( ! ( await this . getKeyBackupStatus ( ) ) ) {
554
+ if ( ! ( await this . isKeyBackupUploadActive ( ) ) ) {
516
555
dis . dispatch ( { action : Action . ReportKeyBackupNotEnabled } ) ;
517
556
}
518
557
} ;
519
558
520
559
/**
521
560
* Is key backup enabled? Use a cached answer if we have one.
522
561
*/
523
- private getKeyBackupStatus = async ( ) : Promise < boolean > => {
562
+ private isKeyBackupUploadActive = async ( ) : Promise < boolean > => {
524
563
if ( ! this . client ) {
525
564
// To preserve existing behaviour, if there is no client, we
526
- // pretend key storage is on.
565
+ // pretend key backup upload is on.
527
566
//
528
567
// Someone looking to improve this code could try throwing an error
529
568
// here since we don't expect client to be undefined.
530
569
return true ;
531
570
}
532
571
572
+ const crypto = this . client . getCrypto ( ) ;
573
+ if ( ! crypto ) {
574
+ // If there is no crypto, there is no key backup
575
+ return false ;
576
+ }
577
+
533
578
// If we've already cached the answer, return it.
534
- if ( this . cachedKeyBackupStatus !== undefined ) {
535
- return this . cachedKeyBackupStatus ;
579
+ if ( this . cachedKeyBackupUploadActive !== undefined ) {
580
+ return this . cachedKeyBackupUploadActive ;
536
581
}
537
582
538
583
// Fetch the answer and cache it
539
- const activeKeyBackupVersion = await this . client . getCrypto ( ) ? .getActiveSessionBackupVersion ( ) ;
540
- this . cachedKeyBackupStatus = ! ! activeKeyBackupVersion ;
584
+ const activeKeyBackupVersion = await crypto . getActiveSessionBackupVersion ( ) ;
585
+ this . cachedKeyBackupUploadActive = ! ! activeKeyBackupVersion ;
541
586
542
- return this . cachedKeyBackupStatus ;
587
+ return this . cachedKeyBackupUploadActive ;
543
588
} ;
544
- private cachedKeyBackupStatus : boolean | undefined = undefined ;
589
+ private cachedKeyBackupUploadActive : boolean | undefined = undefined ;
545
590
546
591
private onRecordClientInformationSettingChange : CallbackFn = (
547
592
_originalSettingName ,
0 commit comments