1
1
import type {
2
+ AccountsControllerAccountAddedEvent ,
3
+ AccountsControllerAccountRenamedEvent ,
2
4
AccountsControllerListAccountsAction ,
3
5
AccountsControllerUpdateAccountMetadataAction ,
4
- AccountsControllerAccountRenamedEvent ,
5
- AccountsControllerAccountAddedEvent ,
6
6
} from '@metamask/accounts-controller' ;
7
7
import type {
8
8
ControllerGetStateAction ,
@@ -12,10 +12,10 @@ import type {
12
12
} from '@metamask/base-controller' ;
13
13
import { BaseController } from '@metamask/base-controller' ;
14
14
import {
15
+ type KeyringControllerAddNewAccountAction ,
15
16
type KeyringControllerGetStateAction ,
16
17
type KeyringControllerLockEvent ,
17
18
type KeyringControllerUnlockEvent ,
18
- type KeyringControllerAddNewAccountAction ,
19
19
} from '@metamask/keyring-controller' ;
20
20
import type { InternalAccount } from '@metamask/keyring-internal-api' ;
21
21
import type {
@@ -26,22 +26,29 @@ import type {
26
26
NetworkControllerUpdateNetworkAction ,
27
27
} from '@metamask/network-controller' ;
28
28
import type { HandleSnapRequest } from '@metamask/snaps-controllers' ;
29
+ import type { Eip1024EncryptedData } from '@metamask/utils' ;
29
30
30
31
import { createSHA256Hash } from '../../shared/encryption' ;
32
+ import type { KeyStore } from '../../shared/encryption/key-storage' ;
33
+ import { ERC1024WrappedKeyStore } from '../../shared/encryption/key-storage' ;
31
34
import type { UserStorageFeatureKeys } from '../../shared/storage-schema' ;
32
35
import {
33
36
type UserStoragePathWithFeatureAndKey ,
34
37
type UserStoragePathWithFeatureOnly ,
35
38
} from '../../shared/storage-schema' ;
36
39
import type { NativeScrypt } from '../../shared/types/encryption' ;
37
- import { createSnapSignMessageRequest } from '../authentication/auth-snap-requests' ;
40
+ import {
41
+ createSnapDecryptMessageRequest ,
42
+ createSnapEncryptionPublicKeyRequest ,
43
+ createSnapSignMessageRequest ,
44
+ } from '../authentication/auth-snap-requests' ;
38
45
import type {
39
46
AuthenticationControllerGetBearerToken ,
40
47
AuthenticationControllerGetSessionProfile ,
41
48
AuthenticationControllerIsSignedIn ,
42
49
AuthenticationControllerPerformSignIn ,
43
50
AuthenticationControllerPerformSignOut ,
44
- } from '../authentication/AuthenticationController ' ;
51
+ } from '../authentication' ;
45
52
import {
46
53
saveInternalAccountToUserStorage ,
47
54
syncInternalAccountsWithUserStorage ,
@@ -102,6 +109,10 @@ export type UserStorageControllerState = {
102
109
* Condition used to ensure that we do not perform any network sync mutations until we have synced at least once
103
110
*/
104
111
hasNetworkSyncingSyncedAtLeastOnce ?: boolean ;
112
+ /**
113
+ * Content keys used to encrypt/decrypt user storage content. These are wrapped while at rest.
114
+ */
115
+ encryptedContentKeys : Record < string , string > ;
105
116
} ;
106
117
107
118
export const defaultState : UserStorageControllerState = {
@@ -110,6 +121,7 @@ export const defaultState: UserStorageControllerState = {
110
121
hasAccountSyncingSyncedAtLeastOnce : false ,
111
122
isAccountSyncingReadyToBeDispatched : false ,
112
123
isAccountSyncingInProgress : false ,
124
+ encryptedContentKeys : { } ,
113
125
} ;
114
126
115
127
const metadata : StateMetadata < UserStorageControllerState > = {
@@ -137,6 +149,10 @@ const metadata: StateMetadata<UserStorageControllerState> = {
137
149
persist : true ,
138
150
anonymous : false ,
139
151
} ,
152
+ encryptedContentKeys : {
153
+ persist : true ,
154
+ anonymous : false ,
155
+ } ,
140
156
} ;
141
157
142
158
type ControllerConfig = {
@@ -313,6 +329,79 @@ export default class UserStorageController extends BaseController<
313
329
isNetworkSyncingEnabled : false ,
314
330
} ;
315
331
332
+ #_snapPublicKeyCache: string | null = null ;
333
+
334
+ #keyWrapping = {
335
+ /**
336
+ * Returns the snap Encryption public key.
337
+ *
338
+ * @returns The snap Encryption public key.
339
+ */
340
+ snapGetEncryptionPublicKey : async ( ) : Promise < string > => {
341
+ if ( this . #_snapPublicKeyCache) {
342
+ return this . #_snapPublicKeyCache;
343
+ }
344
+
345
+ if ( ! this . #isUnlocked) {
346
+ throw new Error (
347
+ '#snapGetEncryptionPublicKey - unable to call snap, wallet is locked' ,
348
+ ) ;
349
+ }
350
+
351
+ const result = ( await this . messagingSystem . call (
352
+ 'SnapController:handleRequest' ,
353
+ createSnapEncryptionPublicKeyRequest ( ) ,
354
+ ) ) as string ;
355
+
356
+ this . #_snapPublicKeyCache = result ;
357
+
358
+ return result ;
359
+ } ,
360
+
361
+ /**
362
+ * Decrypts a message using the message signing snap.
363
+ *
364
+ * @param data - Eip1024EncryptedData - The encrypted data.
365
+ * @returns The decrypted message, if it was intended for this wallet, null otherwise. TODO: check error scenarios
366
+ */
367
+ snapDecryptMessage : async ( data : Eip1024EncryptedData ) : Promise < string > => {
368
+ if ( ! this . #isUnlocked) {
369
+ throw new Error (
370
+ '#snapDecryptMessage - unable to call snap, wallet is locked' ,
371
+ ) ;
372
+ }
373
+
374
+ const result = ( await this . messagingSystem . call (
375
+ 'SnapController:handleRequest' ,
376
+ createSnapDecryptMessageRequest ( data ) ,
377
+ ) ) as string ;
378
+
379
+ return result ;
380
+ } ,
381
+
382
+ loadWrappedKey : async ( keyRef : string ) : Promise < string | null > => {
383
+ return this . state . encryptedContentKeys [ keyRef ] ?? null ;
384
+ } ,
385
+
386
+ storeWrappedKey : ( keyRef : string , wrappedKey : string ) : Promise < void > => {
387
+ return new Promise ( ( resolve ) => {
388
+ this . update ( ( state ) => {
389
+ state . encryptedContentKeys [ keyRef ] = wrappedKey ;
390
+ resolve ( ) ;
391
+ } ) ;
392
+ } ) ;
393
+ } ,
394
+
395
+ getWrappedKeyStore : ( ) : KeyStore => {
396
+ return new ERC1024WrappedKeyStore ( {
397
+ decryptMessage : this . #keyWrapping. snapDecryptMessage ,
398
+ getPublicKey : this . #keyWrapping. snapGetEncryptionPublicKey ,
399
+ getItem : this . #keyWrapping. loadWrappedKey ,
400
+ setItem : this . #keyWrapping. storeWrappedKey ,
401
+ } ) ;
402
+ } ,
403
+ } ;
404
+
316
405
#auth = {
317
406
getBearerToken : async ( ) => {
318
407
return await this . messagingSystem . call (
@@ -374,7 +463,9 @@ export default class UserStorageController extends BaseController<
374
463
} ,
375
464
} ;
376
465
377
- #nativeScryptCrypto: NativeScrypt | undefined = undefined ;
466
+ #nativeScryptCrypto: NativeScrypt | undefined ;
467
+
468
+ #keyStore: KeyStore | undefined ;
378
469
379
470
getMetaMetricsState : ( ) => boolean ;
380
471
@@ -385,6 +476,7 @@ export default class UserStorageController extends BaseController<
385
476
config,
386
477
getMetaMetricsState,
387
478
nativeScryptCrypto,
479
+ keyStore,
388
480
} : {
389
481
messenger : UserStorageControllerMessenger ;
390
482
state ?: UserStorageControllerState ;
@@ -395,6 +487,7 @@ export default class UserStorageController extends BaseController<
395
487
} ;
396
488
getMetaMetricsState : ( ) => boolean ;
397
489
nativeScryptCrypto ?: NativeScrypt ;
490
+ keyStore ?: KeyStore ;
398
491
} ) {
399
492
super ( {
400
493
messenger,
@@ -432,6 +525,8 @@ export default class UserStorageController extends BaseController<
432
525
! this . state . hasNetworkSyncingSyncedAtLeastOnce ,
433
526
} ) ;
434
527
}
528
+
529
+ this . #keyStore = keyStore ?? this . #keyWrapping. getWrappedKeyStore ( ) ;
435
530
}
436
531
437
532
/**
@@ -491,6 +586,7 @@ export default class UserStorageController extends BaseController<
491
586
storageKey,
492
587
bearerToken,
493
588
nativeScryptCrypto : this . #nativeScryptCrypto,
589
+ keyStore : this . #keyStore,
494
590
} ;
495
591
}
496
592
@@ -581,6 +677,7 @@ export default class UserStorageController extends BaseController<
581
677
bearerToken,
582
678
storageKey,
583
679
nativeScryptCrypto : this . #nativeScryptCrypto,
680
+ keyStore : this . #keyStore,
584
681
} ) ;
585
682
586
683
return result ;
@@ -606,6 +703,7 @@ export default class UserStorageController extends BaseController<
606
703
bearerToken,
607
704
storageKey,
608
705
nativeScryptCrypto : this . #nativeScryptCrypto,
706
+ keyStore : this . #keyStore,
609
707
} ) ;
610
708
611
709
return result ;
@@ -633,6 +731,7 @@ export default class UserStorageController extends BaseController<
633
731
bearerToken,
634
732
storageKey,
635
733
nativeScryptCrypto : this . #nativeScryptCrypto,
734
+ keyStore : this . #keyStore,
636
735
} ) ;
637
736
}
638
737
@@ -660,6 +759,7 @@ export default class UserStorageController extends BaseController<
660
759
bearerToken,
661
760
storageKey,
662
761
nativeScryptCrypto : this . #nativeScryptCrypto,
762
+ keyStore : this . #keyStore,
663
763
} ) ;
664
764
}
665
765
@@ -730,6 +830,7 @@ export default class UserStorageController extends BaseController<
730
830
bearerToken,
731
831
storageKey,
732
832
nativeScryptCrypto : this . #nativeScryptCrypto,
833
+ keyStore : this . #keyStore,
733
834
} ) ;
734
835
}
735
836
0 commit comments