@@ -9,7 +9,7 @@ import * as sinon from 'sinon';
99import * as configModule from '../../../initConfig' ;
1010import { DklsTypes , DklsUtils } from '@bitgo-beta/sdk-lib-mpc' ;
1111
12- describe ( 'recoveryMpcV2' , async ( ) => {
12+ describe ( 'recoveryMpcV2' , ( ) => {
1313 let cfg : AdvancedWalletManagerConfig ;
1414 let app : express . Application ;
1515 let agent : request . SuperAgentTest ;
@@ -20,35 +20,44 @@ describe('recoveryMpcV2', async () => {
2020 const cosmosLikeCoin = 'tsei' ;
2121 const accessToken = 'test-token' ;
2222
23- // sinon stubs
23+ // sinon sandbox
24+ const sandbox = sinon . createSandbox ( ) ;
2425 let configStub : sinon . SinonStub ;
2526
2627 // key provider nocks setup
27- const [ userShare , backupShare ] = await DklsUtils . generateDKGKeyShares ( ) ;
28- const userKeyShare = userShare . getKeyShare ( ) . toString ( 'base64' ) ;
29- const backupKeyShare = backupShare . getKeyShare ( ) . toString ( 'base64' ) ;
30- const commonKeychain = DklsTypes . getCommonKeychain ( userShare . getKeyShare ( ) ) ;
31-
32- const mockKeyProviderUserResponse = {
33- prv : JSON . stringify ( userKeyShare ) ,
34- pub : commonKeychain ,
35- source : 'user' ,
36- type : 'tss' ,
37- } ;
38-
39- const mockKeyProviderBackupResponse = {
40- prv : JSON . stringify ( backupKeyShare ) ,
41- pub : commonKeychain ,
42- source : 'backup' ,
43- type : 'tss' ,
44- } ;
45- const input = {
46- txHex :
47- '02f6824268018502540be4008504a817c80083030d409443442e403d64d29c4f64065d0c1a0e8edc03d6c88801550f7dca700000823078c0' ,
48- pub : commonKeychain ,
49- } ;
28+ let userKeyShare : string ;
29+ let backupKeyShare : string ;
30+ let commonKeychain : string ;
31+ let mockKeyProviderUserResponse : { prv : string ; pub : string ; source : string ; type : string } ;
32+ let mockKeyProviderBackupResponse : { prv : string ; pub : string ; source : string ; type : string } ;
33+ let input : { txHex : string ; pub : string } ;
5034
5135 before ( async ( ) => {
36+ const [ userShare , backupShare ] = await DklsUtils . generateDKGKeyShares ( ) ;
37+ userKeyShare = userShare . getKeyShare ( ) . toString ( 'base64' ) ;
38+ backupKeyShare = backupShare . getKeyShare ( ) . toString ( 'base64' ) ;
39+ commonKeychain = DklsTypes . getCommonKeychain ( userShare . getKeyShare ( ) ) ;
40+
41+ mockKeyProviderUserResponse = {
42+ prv : JSON . stringify ( userKeyShare ) ,
43+ pub : commonKeychain ,
44+ source : 'user' ,
45+ type : 'tss' ,
46+ } ;
47+
48+ mockKeyProviderBackupResponse = {
49+ prv : JSON . stringify ( backupKeyShare ) ,
50+ pub : commonKeychain ,
51+ source : 'backup' ,
52+ type : 'tss' ,
53+ } ;
54+
55+ input = {
56+ txHex :
57+ '02f6824268018502540be4008504a817c80083030d409443442e403d64d29c4f64065d0c1a0e8edc03d6c88801550f7dca700000823078c0' ,
58+ pub : commonKeychain ,
59+ } ;
60+
5261 // nock config
5362 nock . disableNetConnect ( ) ;
5463 nock . enableNetConnect ( '127.0.0.1' ) ;
@@ -67,7 +76,7 @@ describe('recoveryMpcV2', async () => {
6776 recoveryMode : true ,
6877 } ;
6978
70- configStub = sinon . stub ( configModule , 'initConfig' ) . returns ( cfg ) ;
79+ configStub = sandbox . stub ( configModule , 'initConfig' ) . returns ( cfg ) ;
7180
7281 // app setup
7382 app = advancedWalletManagerApp ( cfg ) ;
@@ -79,7 +88,7 @@ describe('recoveryMpcV2', async () => {
7988 } ) ;
8089
8190 after ( ( ) => {
82- configStub . restore ( ) ;
91+ sandbox . restore ( ) ;
8392 } ) ;
8493
8594 // happy path test
@@ -132,6 +141,61 @@ describe('recoveryMpcV2', async () => {
132141 backupKeyProviderNock . isDone ( ) . should . be . true ( ) ;
133142 } ) ;
134143
144+ it ( 'should route backup key retrieval to backup KMS when configured' , async ( ) => {
145+ const kmsUrl = 'http://kms.invalid' ;
146+ const backupKmsUrl = 'http://backup-kms.invalid' ;
147+
148+ const mockKmsUserResponse = {
149+ prv : JSON . stringify ( userKeyShare ) ,
150+ pub : commonKeychain ,
151+ source : 'user' ,
152+ type : 'tss' ,
153+ } ;
154+
155+ const mockKmsBackupResponse = {
156+ prv : JSON . stringify ( backupKeyShare ) ,
157+ pub : commonKeychain ,
158+ source : 'backup' ,
159+ type : 'tss' ,
160+ } ;
161+
162+ // Reconfigure app with backup KMS URL
163+ const dualCfg : AdvancedWalletManagerConfig = {
164+ ...cfg ,
165+ keyProviderUrl : kmsUrl ,
166+ backupKmsUrl,
167+ } ;
168+ configStub . returns ( dualCfg ) ;
169+ const dualApp = advancedWalletManagerApp ( dualCfg ) ;
170+ const dualAgent = request . agent ( dualApp ) ;
171+
172+ // User key served from primary KMS
173+ const userKmsNock = nock ( kmsUrl )
174+ . get ( `/key/${ input . pub } ` )
175+ . query ( { source : 'user' } )
176+ . reply ( 200 , mockKmsUserResponse )
177+ . persist ( ) ;
178+
179+ // Backup key served from backup KMS
180+ const backupKmsNock = nock ( backupKmsUrl )
181+ . get ( `/key/${ input . pub } ` )
182+ . query ( { source : 'backup' } )
183+ . reply ( 200 , mockKmsBackupResponse )
184+ . persist ( ) ;
185+
186+ const response = await dualAgent
187+ . post ( `/api/${ ethLikeCoin } /mpcv2/recovery` )
188+ . set ( 'Authorization' , `Bearer ${ accessToken } ` )
189+ . send ( input ) ;
190+
191+ response . status . should . equal ( 200 ) ;
192+ response . body . should . have . property ( 'txHex' ) ;
193+ response . body . should . have . property ( 'stringifiedSignature' ) ;
194+
195+ userKmsNock . isDone ( ) . should . be . true ( ) ;
196+ backupKmsNock . isDone ( ) . should . be . true ( ) ;
197+ } ) ;
198+
135199 // failure test case
136200 it ( 'should throw 400 Bad Request if failed to construct eth transaction from message hex' , async ( ) => {
137201 const input = {
0 commit comments