1+ import nock from 'nock' ;
2+ import 'should' ;
3+ import * as sinon from 'sinon' ;
4+ import * as express from 'express' ;
5+ import * as request from 'supertest' ;
6+ import { AppMode , EnclavedConfig , TlsMode } from '../../../shared/types' ;
7+ import { app as enclavedApp } from '../../../enclavedApp' ;
8+
9+ describe ( 'MPC Initialize' , ( ) => {
10+ let agent : request . SuperAgentTest ;
11+ let app : express . Application ;
12+ let cfg : EnclavedConfig ;
13+ const kmsUrl = 'https://kms.com' ;
14+
15+ // Mock BitGo object with encrypt method
16+ const mockBitgo = {
17+ encrypt : sinon . stub ( ) . returns ( 'encryptedTestData' ) ,
18+ } ;
19+
20+ // Sample data key response from KMS
21+ const mockDataKeyResponse = {
22+ plaintextKey :
23+ '75,212,73,155,238,206,208,243,103,70,241,121,120,187,188,212,215,169,49,49,158,151,220,182,129,163,146,206,31,176,24,114' ,
24+ encryptedKey :
25+ '1,2,3,0,120,222,140,157,217,111,195,208,47,200,213,217,82,189,16,171,207,16,138,46,228,224,190,138,63,132,239,80,164,8,124,105,140,1,7,221,102,148,133,184,75,102,109,103,40,227,59,0,4,66,0,0,0,126,48,124,6,9,42,134,72,134,247,13,1,7,6,160,111,48,109,2,1,0,48,104,6,9,42,134,72,134,247,13,1,7,1,48,30,6,9,96,134,72,1,101,3,4,1,46,48,17,4,12,182,95,181,221,231,6,80,219,103,86,56,83,2,1,16,128,59,214,99,174,74,198,0,141,19,136,106,211,254,68,242,173,237,13,192,176,121,74,142,141,240,161,253,119,56,144,29,201,133,58,246,2,202,166,201,161,193,29,162,12,243,174,67,27,114,208,168,214,248,170,203,214,117,49,128,218' ,
26+ } ;
27+
28+ before ( ( ) => {
29+ // app config
30+ cfg = {
31+ appMode : AppMode . ENCLAVED ,
32+ port : 0 , // Let OS assign a free port
33+ bind : 'localhost' ,
34+ timeout : 60000 ,
35+ httpLoggerFile : '' ,
36+ kmsUrl : kmsUrl ,
37+ tlsMode : TlsMode . DISABLED ,
38+ allowSelfSigned : true ,
39+ } ;
40+
41+ // configStub = sinon.stub(configModule, 'initConfig').returns(cfg);
42+
43+ app = enclavedApp ( cfg ) ;
44+ agent = request . agent ( app ) ;
45+ } ) ;
46+
47+ beforeEach ( ( ) => {
48+ nock . disableNetConnect ( ) ;
49+ nock . enableNetConnect ( '127.0.0.1' ) ;
50+ // Mock KMS service
51+ nock ( kmsUrl ) . post ( '/generateDataKey' ) . reply ( 200 , mockDataKeyResponse ) ;
52+ } ) ;
53+
54+ afterEach ( ( ) => {
55+ sinon . restore ( ) ;
56+ nock . cleanAll ( ) ;
57+ } ) ;
58+
59+ it ( 'should successfully initialize MPC key generation for user source' , async ( ) => {
60+ // Mock request object
61+ const result = await agent . post ( '/api/tsol/mpc/key/initialize' ) . send ( {
62+ source : 'user' ,
63+ bitgoGpgPub :
64+ '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' +
65+ '\n' +
66+ 'xk8EYqEU5hMFK4EEAAoCAwQDdbAIZrsblEXIavyg2go6p9oG0SqWTgFsdHTc\n' +
67+ 'BhqdIS/WjQ8pj75q+vLqFtV9hlImYGInsIWh97fsigzB2owyzRhoc20gPGhz\n' +
68+ 'bUB0ZXN0LmJpdGdvLmNvbT7ChAQTEwgAFQUCYqEU5wILCQIVCAIWAAIbAwIe\n' +
69+ 'AQAhCRCJNRsIDGunexYhBHRL5D/8nRM3opQnXok1GwgMa6d7tg8A/24A9awq\n' +
70+ 'SCJx7RddiUzFHcKhVvvo3R5N7bHaOGP3TP79AP0TavF2WzhUXmZSjt3IK23O\n' +
71+ '7/aknbijVeq52ghbWb1SwsJ1BBATCAAGBQJioRTnACEJEAWuA35KJgtgFiEE\n' +
72+ 'ZttLPR0KcYvjgvJCBa4DfkomC2BsrwD/Z+43zOw+WpfPHxe+ypyVog5fnOKl\n' +
73+ 'XwleH6zDvqUWmWkA/iaHC6ullYkSG4Mv68k6qbtgR/pms/X7rkfa0QQFJy5p\n' +
74+ 'zlMEYqEU5hIFK4EEAAoCAwSsLqmfonjMF3o0nZ5JHvLpmfTA1RIVDsAEoRON\n' +
75+ 'tZA6rAA23pGl6s3Iyt4/fX9Adzoh3EElOjMsgi8Aj3dFpuqiAwEIB8J4BBgT\n' +
76+ 'CAAJBQJioRTnAhsMACEJEIk1GwgMa6d7FiEEdEvkP/ydEzeilCdeiTUbCAxr\n' +
77+ 'p3vM7AD9GPp6HhYNEh2VVCDtFSt14Bni5FVM5icpVDo6w9ibvWAA/2Ti3Jv4\n' +
78+ 'IhIxl81/wqAgqigIblrz6vjtagr9/ykXQCW3\n' +
79+ '=skCo\n' +
80+ '-----END PGP PUBLIC KEY BLOCK-----\n' ,
81+ } ) ;
82+
83+ // Assert the response structure
84+ result . should . have . property ( 'statusCode' , 200 ) ;
85+ result . body . should . have . property ( 'bitgoPayload' ) ;
86+ result . body . bitgoPayload . from . should . equal ( 'user' ) ;
87+ result . body . bitgoPayload . to . should . equal ( 'bitgo' ) ;
88+ result . body . bitgoPayload . should . have . property ( 'privateShare' ) ;
89+ result . body . bitgoPayload . privateShare . should . not . be . empty ( ) ;
90+ } ) ;
91+
92+ it ( 'should successfully initialize MPC key generation for backup source' , async ( ) => {
93+ // Mock request object
94+ const result = await agent . post ( '/api/tsol/mpc/key/initialize' ) . send ( {
95+ source : 'backup' ,
96+ bitgoGpgPub :
97+ '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' +
98+ '\n' +
99+ 'xk8EYqEU5hMFK4EEAAoCAwQDdbAIZrsblEXIavyg2go6p9oG0SqWTgFsdHTc\n' +
100+ 'BhqdIS/WjQ8pj75q+vLqFtV9hlImYGInsIWh97fsigzB2owyzRhoc20gPGhz\n' +
101+ 'bUB0ZXN0LmJpdGdvLmNvbT7ChAQTEwgAFQUCYqEU5wILCQIVCAIWAAIbAwIe\n' +
102+ 'AQAhCRCJNRsIDGunexYhBHRL5D/8nRM3opQnXok1GwgMa6d7tg8A/24A9awq\n' +
103+ 'SCJx7RddiUzFHcKhVvvo3R5N7bHaOGP3TP79AP0TavF2WzhUXmZSjt3IK23O\n' +
104+ '7/aknbijVeq52ghbWb1SwsJ1BBATCAAGBQJioRTnACEJEAWuA35KJgtgFiEE\n' +
105+ 'ZttLPR0KcYvjgvJCBa4DfkomC2BsrwD/Z+43zOw+WpfPHxe+ypyVog5fnOKl\n' +
106+ 'XwleH6zDvqUWmWkA/iaHC6ullYkSG4Mv68k6qbtgR/pms/X7rkfa0QQFJy5p\n' +
107+ 'zlMEYqEU5hIFK4EEAAoCAwSsLqmfonjMF3o0nZ5JHvLpmfTA1RIVDsAEoRON\n' +
108+ 'tZA6rAA23pGl6s3Iyt4/fX9Adzoh3EElOjMsgi8Aj3dFpuqiAwEIB8J4BBgT\n' +
109+ 'CAAJBQJioRTnAhsMACEJEIk1GwgMa6d7FiEEdEvkP/ydEzeilCdeiTUbCAxr\n' +
110+ 'p3vM7AD9GPp6HhYNEh2VVCDtFSt14Bni5FVM5icpVDo6w9ibvWAA/2Ti3Jv4\n' +
111+ 'IhIxl81/wqAgqigIblrz6vjtagr9/ykXQCW3\n' +
112+ '=skCo\n' +
113+ '-----END PGP PUBLIC KEY BLOCK-----\n' ,
114+ counterPartyGpgPub :
115+ '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' +
116+ '\n' +
117+ 'xk8EYqEU5hMFK4EEAAoCAwQDdbAIZrsblEXIavyg2go6p9oG0SqWTgFsdHTc\n' +
118+ 'BhqdIS/WjQ8pj75q+vLqFtV9hlImYGInsIWh97fsigzB2owyzRhoc20gPGhz\n' +
119+ 'bUB0ZXN0LmJpdGdvLmNvbT7ChAQTEwgAFQUCYqEU5wILCQIVCAIWAAIbAwIe\n' +
120+ 'AQAhCRCJNRsIDGunexYhBHRL5D/8nRM3opQnXok1GwgMa6d7tg8A/24A9awq\n' +
121+ 'SCJx7RddiUzFHcKhVvvo3R5N7bHaOGP3TP79AP0TavF2WzhUXmZSjt3IK23O\n' +
122+ '7/aknbijVeq52ghbWb1SwsJ1BBATCAAGBQJioRTnACEJEAWuA35KJgtgFiEE\n' +
123+ 'ZttLPR0KcYvjgvJCBa4DfkomC2BsrwD/Z+43zOw+WpfPHxe+ypyVog5fnOKl\n' +
124+ 'XwleH6zDvqUWmWkA/iaHC6ullYkSG4Mv68k6qbtgR/pms/X7rkfa0QQFJy5p\n' +
125+ 'zlMEYqEU5hIFK4EEAAoCAwSsLqmfonjMF3o0nZ5JHvLpmfTA1RIVDsAEoRON\n' +
126+ 'tZA6rAA23pGl6s3Iyt4/fX9Adzoh3EElOjMsgi8Aj3dFpuqiAwEIB8J4BBgT\n' +
127+ 'CAAJBQJioRTnAhsMACEJEIk1GwgMa6d7FiEEdEvkP/ydEzeilCdeiTUbCAxr\n' +
128+ 'p3vM7AD9GPp6HhYNEh2VVCDtFSt14Bni5FVM5icpVDo6w9ibvWAA/2Ti3Jv4\n' +
129+ 'IhIxl81/wqAgqigIblrz6vjtagr9/ykXQCW3\n' +
130+ '=skCo\n' +
131+ '-----END PGP PUBLIC KEY BLOCK-----\n' ,
132+ } ) ;
133+
134+ // Assert the response structure
135+ result . should . have . property ( 'statusCode' , 200 ) ;
136+ result . body . should . have . property ( 'bitgoPayload' ) ;
137+ result . body . bitgoPayload . from . should . equal ( 'backup' ) ;
138+ result . body . bitgoPayload . to . should . equal ( 'bitgo' ) ;
139+ result . body . bitgoPayload . should . have . property ( 'privateShare' ) ;
140+ result . body . bitgoPayload . privateShare . should . not . be . empty ( ) ;
141+
142+ // For backup source with counterPartyGpgPub, counterPartyKeyShare should be defined
143+ result . body . should . have . property ( 'counterPartyKeyShare' ) ;
144+ result . body . counterPartyKeyShare . from . should . equal ( 'backup' ) ;
145+ result . body . counterPartyKeyShare . to . should . equal ( 'user' ) ;
146+ result . body . counterPartyKeyShare . should . have . property ( 'privateShare' ) ;
147+ result . body . counterPartyKeyShare . privateShare . should . not . be . empty ( ) ;
148+ } ) ;
149+
150+ it ( 'should fail when backup source is missing counterPartyGpgPub' , async ( ) => {
151+ // Mock request without the required counterPartyGpgPub
152+ const result = await agent . post ( '/api/tsol/mpc/key/initialize' ) . send ( {
153+ source : 'backup' ,
154+ bitgoGpgPub :
155+ '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' +
156+ '\n' +
157+ 'xk8EYqEU5hMFK4EEAAoCAwQDdbAIZrsblEXIavyg2go6p9oG0SqWTgFsdHTc\n' +
158+ 'BhqdIS/WjQ8pj75q+vLqFtV9hlImYGInsIWh97fsigzB2owyzRhoc20gPGhz\n' +
159+ 'bUB0ZXN0LmJpdGdvLmNvbT7ChAQTEwgAFQUCYqEU5wILCQIVCAIWAAIbAwIe\n' +
160+ 'AQAhCRCJNRsIDGunexYhBHRL5D/8nRM3opQnXok1GwgMa6d7tg8A/24A9awq\n' +
161+ 'SCJx7RddiUzFHcKhVvvo3R5N7bHaOGP3TP79AP0TavF2WzhUXmZSjt3IK23O\n' +
162+ '7/aknbijVeq52ghbWb1SwsJ1BBATCAAGBQJioRTnACEJEAWuA35KJgtgFiEE\n' +
163+ 'ZttLPR0KcYvjgvJCBa4DfkomC2BsrwD/Z+43zOw+WpfPHxe+ypyVog5fnOKl\n' +
164+ 'XwleH6zDvqUWmWkA/iaHC6ullYkSG4Mv68k6qbtgR/pms/X7rkfa0QQFJy5p\n' +
165+ 'zlMEYqEU5hIFK4EEAAoCAwSsLqmfonjMF3o0nZ5JHvLpmfTA1RIVDsAEoRON\n' +
166+ 'tZA6rAA23pGl6s3Iyt4/fX9Adzoh3EElOjMsgi8Aj3dFpuqiAwEIB8J4BBgT\n' +
167+ 'CAAJBQJioRTnAhsMACEJEIk1GwgMa6d7FiEEdEvkP/ydEzeilCdeiTUbCAxr\n' +
168+ 'p3vM7AD9GPp6HhYNEh2VVCDtFSt14Bni5FVM5icpVDo6w9ibvWAA/2Ti3Jv4\n' +
169+ 'IhIxl81/wqAgqigIblrz6vjtagr9/ykXQCW3\n' +
170+ '=skCo\n' +
171+ '-----END PGP PUBLIC KEY BLOCK-----\n' ,
172+ } ) ;
173+
174+ // Expect an error
175+ result . should . have . property ( 'statusCode' , 400 ) ;
176+ result . body . should . have . property ( 'error' ) ;
177+ result . body . error . should . equal ( 'BadRequestError' ) ;
178+ result . body . details . should . containEql ( 'gpgKey is required on backup key share generation' ) ;
179+ } ) ;
180+ } ) ;
0 commit comments