|
1 | | -import { AppMode, AdvancedWalletManagerConfig, TlsMode } from '../../../initConfig'; |
2 | | -import { app as expressApp } from '../../../advancedWalletManagerApp'; |
3 | | - |
4 | | -import express from 'express'; |
5 | | -import nock from 'nock'; |
6 | 1 | import 'should'; |
7 | 2 | import * as request from 'supertest'; |
8 | | -import { DklsTypes, DklsUtils } from '@bitgo-beta/sdk-lib-mpc'; |
| 3 | +import nock from 'nock'; |
| 4 | +import { app as expressApp } from '../../../advancedWalletManagerApp'; |
| 5 | +import { AdvancedWalletManagerConfig, AppMode, TlsMode } from '../../../shared/types'; |
9 | 6 |
|
10 | | -describe('recoveryMpc', async () => { |
11 | | - let cfg: AdvancedWalletManagerConfig; |
12 | | - let app: express.Application; |
| 7 | +describe('recoveryMpc', () => { |
13 | 8 | let agent: request.SuperAgentTest; |
14 | 9 |
|
15 | 10 | // test config |
16 | 11 | const kmsUrl = 'http://kms.invalid'; |
17 | | - const eddsaCoin = 'tsol'; |
18 | | - const nonSol = 'tnear'; |
| 12 | + const sol = 'tsol'; |
| 13 | + const sui = 'tsui'; |
19 | 14 | const accessToken = 'test-token'; |
20 | 15 |
|
21 | | - // sinon stubs |
22 | | - // let configStub: sinon.SinonStub; |
23 | | - |
24 | | - // kms nocks setup |
25 | | - const [userShare, backupShare] = await DklsUtils.generateDKGKeyShares(); |
26 | | - const userKeyShare = userShare.getKeyShare().toString('base64'); |
27 | | - const backupKeyShare = backupShare.getKeyShare().toString('base64'); |
28 | | - const commonKeychain = DklsTypes.getCommonKeychain(userShare.getKeyShare()); |
29 | | - |
30 | | - const mockKmsUserResponse = { |
31 | | - prv: JSON.stringify(userKeyShare), |
32 | | - pub: commonKeychain, |
33 | | - source: 'user', |
34 | | - type: 'tss', |
35 | | - }; |
36 | | - |
37 | | - const mockKmsBackupResponse = { |
38 | | - prv: JSON.stringify(backupKeyShare), |
39 | | - pub: commonKeychain, |
40 | | - source: 'backup', |
41 | | - type: 'tss', |
42 | | - }; |
43 | | - const input = { |
44 | | - txHex: |
45 | | - '', |
46 | | - pub: commonKeychain, |
47 | | - }; |
48 | | - |
49 | 16 | before(async () => { |
50 | | - // nock config |
51 | 17 | nock.disableNetConnect(); |
52 | 18 | nock.enableNetConnect('127.0.0.1'); |
53 | 19 |
|
54 | | - // app config |
55 | | - cfg = { |
| 20 | + const config: AdvancedWalletManagerConfig = { |
56 | 21 | appMode: AppMode.ADVANCED_WALLET_MANAGER, |
57 | 22 | port: 0, // Let OS assign a free port |
58 | 23 | bind: 'localhost', |
59 | 24 | timeout: 60000, |
60 | 25 | kmsUrl: kmsUrl, |
61 | 26 | httpLoggerFile: '', |
62 | 27 | tlsMode: TlsMode.DISABLED, |
63 | | - allowSelfSigned: true, |
| 28 | + |
64 | 29 | recoveryMode: true, |
65 | 30 | }; |
66 | 31 |
|
67 | | - // app setup |
68 | | - app = expressApp(cfg); |
| 32 | + const app = expressApp(config); |
69 | 33 | agent = request.agent(app); |
70 | 34 | }); |
71 | 35 |
|
72 | 36 | afterEach(() => { |
73 | 37 | nock.cleanAll(); |
74 | 38 | }); |
75 | 39 |
|
76 | | - // happy path test |
77 | | - it('should be sign a MPC Recovery', async () => { |
78 | | - // nocks for KMS responses |
79 | | - const userKmsNock = nock(kmsUrl) |
80 | | - .get(`/key/${input.pub}`) |
81 | | - .query({ source: 'user', useLocalEncipherment: false }) |
82 | | - .reply(200, mockKmsUserResponse) |
83 | | - .persist(); |
84 | | - const backupKmsNock = nock(kmsUrl) |
85 | | - .get(`/key/${input.pub}`) |
86 | | - .query({ source: 'backup', useLocalEncipherment: false }) |
87 | | - .reply(200, mockKmsBackupResponse) |
88 | | - .persist(); |
89 | | - |
90 | | - const eddsaSignatureResponse = await agent |
91 | | - .post(`/api/${eddsaCoin}/mpc/recovery`) |
92 | | - .set('Authorization', `Bearer ${accessToken}`) |
93 | | - .send(input); |
94 | | - |
95 | | - eddsaSignatureResponse.status.should.equal(200); |
96 | | - eddsaSignatureResponse.body.should.have.property('txHex'); |
97 | | - eddsaSignatureResponse.body.txHex.should.equal(input.txHex); |
| 40 | + after(() => { |
| 41 | + nock.enableNetConnect(); |
| 42 | + }); |
| 43 | + |
| 44 | + describe('ECDSA sol recovery', () => { |
| 45 | + it('should successfully generate MPC solana transactions', async () => { |
| 46 | + const mockKmsUserResponse = { |
| 47 | + prv: '{"uShare":{"i":1,"t":2,"n":3,"y":"85aa6462d927329418f70f6d0863cf6cf33e7da2934f935e5927f1b13062d779","seed":"2f55c80fd6b5583dcde8037b2ee461d2e7d445a4d3e7a9b2a0d3d00b5f534169","chaincode":"66e80f2bf41a5706608352d51ceb07a5aa1729cab6c6993c124d5731546ed9a1"},"bitgoYShare":{"i":1,"j":3,"y":"483e53b72de3aa893df698d0b20b20777fb3d2716cc8483a9e9797174fd52b16","v":"e70696459e46434a2a12cc988e3ae714a61fe96da8a6764d058b849cab50d6dc","u":"49abf8144d265a77cf6d098eff784d6ce56ec77a182f6b39f47d5d8e28f2a802","chaincode":"797348468202f1d7fede0a7851f80162b02e7da306e65075dd864b6789b9bc5b"},"backupYShare":{"i":1,"j":2,"y":"249a9798d0064a989a16cd8f479edf09ffaee73f4175d2ac555ba90ff41b89da","v":"98e31d2b643e40060ba344c6a41fc096ea7e39a1ae879f65e4af645870e90ee0","u":"ac047b1bceab2e1a42d97ab540b39176e545d9c0af4a192aee8e1dae91a4240b","chaincode":"585bdc05c8f84802cbe7b9a1a07d4aa9c5fede93597a622854e9bad83a2d5b78"}}', |
| 48 | + pub: 'b6f5fb808f538a32735a89609e98fab75690a2c79b26f50a54c4cbf0fbca287138b733783f1590e12b4916ef0f6053b22044860117274bda44bd5d711855f174', |
| 49 | + source: 'user', |
| 50 | + type: 'tss', |
| 51 | + }; |
| 52 | + |
| 53 | + const mockKmsBackupResponse = { |
| 54 | + prv: '{"uShare":{"i":2,"t":2,"n":3,"y":"249a9798d0064a989a16cd8f479edf09ffaee73f4175d2ac555ba90ff41b89da","seed":"abab5be2b32d07cf39b2a162af0f78bad8325b2fbdc89d14fd8b4e5767b74097","chaincode":"585bdc05c8f84802cbe7b9a1a07d4aa9c5fede93597a622854e9bad83a2d5b78"},"bitgoYShare":{"i":2,"j":3,"y":"483e53b72de3aa893df698d0b20b20777fb3d2716cc8483a9e9797174fd52b16","v":"e70696459e46434a2a12cc988e3ae714a61fe96da8a6764d058b849cab50d6dc","u":"eb54da28da3da22eb3d61797a02a96264be8940b7115aefbb90b9dd044db7f06","chaincode":"797348468202f1d7fede0a7851f80162b02e7da306e65075dd864b6789b9bc5b"},"userYShare":{"i":2,"j":1,"y":"85aa6462d927329418f70f6d0863cf6cf33e7da2934f935e5927f1b13062d779","v":"76cfdcbf0f769f21c64e0faf0072ebccbcc3aaa844522336af27f8e50ed7ca5f","u":"6ce814af82683423c8d8befd13f6eeeb0cd3f7274d1ebfdd5807fd2e4eaadb08","chaincode":"66e80f2bf41a5706608352d51ceb07a5aa1729cab6c6993c124d5731546ed9a1"}}', |
| 55 | + pub: 'b6f5fb808f538a32735a89609e98fab75690a2c79b26f50a54c4cbf0fbca287138b733783f1590e12b4916ef0f6053b22044860117274bda44bd5d711855f174', |
| 56 | + source: 'backup', |
| 57 | + type: 'tss', |
| 58 | + }; |
| 59 | + |
| 60 | + nock(kmsUrl) |
| 61 | + .get(`/key/${mockKmsUserResponse.pub}`) |
| 62 | + .query({ source: 'user' }) |
| 63 | + .reply(200, mockKmsUserResponse) |
| 64 | + .persist(); |
| 65 | + |
| 66 | + nock(kmsUrl) |
| 67 | + .get(`/key/${mockKmsBackupResponse.pub}`) |
| 68 | + .query({ source: 'backup' }) |
| 69 | + .reply(200, mockKmsBackupResponse) |
| 70 | + .persist(); |
| 71 | + |
| 72 | + const input = { |
| 73 | + commonKeychain: |
| 74 | + 'b6f5fb808f538a32735a89609e98fab75690a2c79b26f50a54c4cbf0fbca287138b733783f1590e12b4916ef0f6053b22044860117274bda44bd5d711855f174', |
| 75 | + unsignedSweepPrebuildTx: { |
| 76 | + txRequests: [ |
| 77 | + { |
| 78 | + unsignedTx: '', |
| 79 | + signableHex: |
| 80 | + 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAECvoOqYkvCPusjYyhX4GdUtzSeVIcx6GkwdpSk8SkU0/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQtFGO2YBsrubq15CKqJLwXG3VEF1aEs36Rao6EaJDLAQECAAAMAgAAALhJxgAAAAAA', |
| 81 | + derivationPath: 'm/0', |
| 82 | + }, |
| 83 | + ], |
| 84 | + }, |
| 85 | + }; |
| 86 | + |
| 87 | + const eddsaSignatureResponse = await agent |
| 88 | + .post(`/api/${sol}/mpc/recovery`) |
| 89 | + .set('Authorization', `Bearer ${accessToken}`) |
| 90 | + .send(input); |
| 91 | + |
| 92 | + eddsaSignatureResponse.status.should.equal(200); |
| 93 | + eddsaSignatureResponse.body.should.have.property('txHex'); |
| 94 | + |
| 95 | + nock.cleanAll(); |
| 96 | + }); |
| 97 | + |
| 98 | + it('should throw 500 Internal Server Error if KMS cannot find user or backup keys', async () => { |
| 99 | + const commonKeychain = |
| 100 | + 'b6f5fb808f538a32735a89609e98fab75690a2c79b26f50a54c4cbf0fbca287138b733783f1590e12b4916ef0f6053b22044860117274bda44bd5d711855f174'; |
| 101 | + const mockKmsUserResponse = {}; |
| 102 | + const mockKmsBackupResponse = {}; |
| 103 | + |
| 104 | + nock(kmsUrl) |
| 105 | + .get(`/key/${commonKeychain}`) |
| 106 | + .query({ source: 'user' }) |
| 107 | + .reply(200, mockKmsUserResponse) |
| 108 | + .persist(); |
| 109 | + |
| 110 | + nock(kmsUrl) |
| 111 | + .get(`/key/${commonKeychain}`) |
| 112 | + .query({ source: 'backup' }) |
| 113 | + .reply(200, mockKmsBackupResponse) |
| 114 | + .persist(); |
| 115 | + |
| 116 | + const input = { |
| 117 | + commonKeychain: |
| 118 | + 'b6f5fb808f538a32735a89609e98fab75690a2c79b26f50a54c4cbf0fbca287138b733783f1590e12b4916ef0f6053b22044860117274bda44bd5d711855f174', |
| 119 | + unsignedSweepPrebuildTx: { |
| 120 | + txRequests: [ |
| 121 | + { |
| 122 | + unsignedTx: '', |
| 123 | + signableHex: |
| 124 | + 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAECvoOqYkvCPusjYyhX4GdUtzSeVIcx6GkwdpSk8SkU0/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQtFGO2YBsrubq15CKqJLwXG3VEF1aEs36Rao6EaJDLAQECAAAMAgAAALhJxgAAAAAA', |
| 125 | + derivationPath: 'm/0', |
| 126 | + }, |
| 127 | + ], |
| 128 | + }, |
| 129 | + }; |
| 130 | + |
| 131 | + const eddsaSignatureResponse = await agent |
| 132 | + .post(`/api/${sol}/mpc/recovery`) |
| 133 | + .set('Authorization', `Bearer ${accessToken}`) |
| 134 | + .send(input); |
| 135 | + |
| 136 | + eddsaSignatureResponse.status.should.equal(500); |
| 137 | + eddsaSignatureResponse.body.should.have.property('error'); |
| 138 | + eddsaSignatureResponse.body.error.should.equal('Internal Server Error'); |
| 139 | + |
| 140 | + nock.cleanAll(); |
| 141 | + }); |
| 142 | + }); |
| 143 | + |
| 144 | + describe('ECDSA sui recovery', () => { |
| 145 | + it('should successfully generate MPC sui transactions', async () => { |
| 146 | + const mockKmsUserResponse = { |
| 147 | + prv: '{"uShare":{"i":1,"t":2,"n":3,"y":"8e10c0d10fb8a5780bba0f62fb86e2a80fd6f04b348985e9174a4f4f66e1baf5","seed":"368eab02c210effbb345d8c3cbe3d00b61292071feb0eafe26d9ce6060145d7b","chaincode":"e32078c8ba161f4c6c10b01abdf8203aed06878bae6a90906be228fd1b196b18"},"bitgoYShare":{"i":1,"j":3,"y":"532ee5aa5be82b9e64c10ff98d3be21901888bbba2293f0db429b8737cbf94ca","v":"72b2a6d7243654f4e80b050f5fa0c9de505b37ebcd7803dfacf22ba8bc60716a","u":"b13b791180c1148405f2137f011831ec5ffd4dd2584f7bef4f5a174debe8df08","chaincode":"87292c10bbdfd6f15e80dd96f3b530aaf0b7b99d933b3d0b61b7a1565b0a89f9"},"backupYShare":{"i":1,"j":2,"y":"5119753ee78a9f43ed2df6bc79d1d69954ada568dce7c3de6aa031ea2f951967","v":"852459fcfe7170cb433cc98115fb2a292b3301834ce89b0e843ad952cca885d1","u":"0854f68dbf402bc928afb86448eab19fbe90fcb387103d1fff35d02af18b230d","chaincode":"e09a186e387c74144c636793294a1c38017e9e4d5c5156f6b6fc824fe90fdaf0"}}', |
| 148 | + pub: 'f2b50b246be21f9819cdf08c721cd5d2dfb01efed33c65abd9030703609eef4c4ae3bd47ae726a5216f4f544daf76d1ddf3cdf769df7249284964ca35f33d001', |
| 149 | + source: 'user', |
| 150 | + type: 'tss', |
| 151 | + }; |
| 152 | + |
| 153 | + const mockKmsBackupResponse = { |
| 154 | + prv: '{"uShare":{"i":2,"t":2,"n":3,"y":"5119753ee78a9f43ed2df6bc79d1d69954ada568dce7c3de6aa031ea2f951967","seed":"e70e6fd6f914b7b854e7b5ab46fff52a530dc3d10aa5a71c2b32559ea349ac4e","chaincode":"e09a186e387c74144c636793294a1c38017e9e4d5c5156f6b6fc824fe90fdaf0"},"bitgoYShare":{"i":2,"j":3,"y":"532ee5aa5be82b9e64c10ff98d3be21901888bbba2293f0db429b8737cbf94ca","v":"72b2a6d7243654f4e80b050f5fa0c9de505b37ebcd7803dfacf22ba8bc60716a","u":"709cfacb0bfa99c38ff319d16e4e2b34ecd8e40025496d21d2932204b785e80d","chaincode":"87292c10bbdfd6f15e80dd96f3b530aaf0b7b99d933b3d0b61b7a1565b0a89f9"},"userYShare":{"i":2,"j":1,"y":"8e10c0d10fb8a5780bba0f62fb86e2a80fd6f04b348985e9174a4f4f66e1baf5","v":"a81795570884a88dc7586c9a49a632a2aea0859eae622c51617387b85e8b5b0a","u":"0857dfc00a1fe3a4a41a752e933788becc6b23c2f5637393906f79b89aa50d0d","chaincode":"e32078c8ba161f4c6c10b01abdf8203aed06878bae6a90906be228fd1b196b18"}}', |
| 155 | + pub: 'f2b50b246be21f9819cdf08c721cd5d2dfb01efed33c65abd9030703609eef4c4ae3bd47ae726a5216f4f544daf76d1ddf3cdf769df7249284964ca35f33d001', |
| 156 | + source: 'backup', |
| 157 | + type: 'tss', |
| 158 | + }; |
| 159 | + |
| 160 | + nock(kmsUrl) |
| 161 | + .get(`/key/${mockKmsUserResponse.pub}`) |
| 162 | + .query({ source: 'user' }) |
| 163 | + .reply(200, mockKmsUserResponse) |
| 164 | + .persist(); |
| 165 | + |
| 166 | + nock(kmsUrl) |
| 167 | + .get(`/key/${mockKmsBackupResponse.pub}`) |
| 168 | + .query({ source: 'backup' }) |
| 169 | + .reply(200, mockKmsBackupResponse) |
| 170 | + .persist(); |
| 171 | + |
| 172 | + const input = { |
| 173 | + commonKeychain: |
| 174 | + 'f2b50b246be21f9819cdf08c721cd5d2dfb01efed33c65abd9030703609eef4c4ae3bd47ae726a5216f4f544daf76d1ddf3cdf769df7249284964ca35f33d001', |
| 175 | + unsignedSweepPrebuildTx: { |
| 176 | + txRequests: [ |
| 177 | + { |
| 178 | + unsignedTx: '', |
| 179 | + signableHex: |
| 180 | + '00000200085c41793b000000000020cc1d71fdfab20a29d084030623a682e86f254f3e6a08134cc037de37fea94b21020200010100000101020000010100cc1d71fdfab20a29d084030623a682e86f254f3e6a08134cc037de37fea94b21011a4951d0006f16326d5b74df71b5c81450b4cc74d9f1c357e6e1665d5ca9a067a711d0140000000020d0402c106771059acc3246a145a7baccd512f499f086976fe768569d751bb00dcc1d71fdfab20a29d084030623a682e86f254f3e6a08134cc037de37fea94b21e803000000000000a48821000000000000', |
| 181 | + derivationPath: 'm/0', |
| 182 | + }, |
| 183 | + ], |
| 184 | + }, |
| 185 | + }; |
| 186 | + |
| 187 | + const eddsaSignatureResponse = await agent |
| 188 | + .post(`/api/${sui}/mpc/recovery`) |
| 189 | + .set('Authorization', `Bearer ${accessToken}`) |
| 190 | + .send(input); |
| 191 | + |
| 192 | + eddsaSignatureResponse.status.should.equal(200); |
| 193 | + eddsaSignatureResponse.body.should.have.property('txHex'); |
| 194 | + }); |
98 | 195 | }); |
99 | 196 | }); |
0 commit comments