Skip to content

Commit 5fb5327

Browse files
committed
chore(mbe): move ebe config checks to middleware
Ticket: WP-4724
1 parent 8488e2d commit 5fb5327

7 files changed

Lines changed: 109 additions & 24 deletions

File tree

src/__tests__/masterBitgoExpress/generateWallet.test.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,6 @@ describe('POST /api/:coin/wallet/generate', () => {
4141
nock.cleanAll();
4242
});
4343

44-
after(() => {
45-
nock.restore();
46-
});
47-
4844
it('should generate a wallet by calling the enclaved express service', async () => {
4945
const userKeychainNock = nock(enclavedExpressUrl)
5046
.post(`/api/${coin}/key/independent`, {
@@ -142,4 +138,35 @@ describe('POST /api/:coin/wallet/generate', () => {
142138
bitgoAddBitGoKeyNock.done();
143139
bitgoAddWalletNock.done();
144140
});
141+
142+
it('should fail when enclaved express client is not configured', async () => {
143+
// Create a config without enclaved express settings
144+
const invalidConfig: Partial<MasterExpressConfig> = {
145+
appMode: AppMode.MASTER_EXPRESS,
146+
port: 0,
147+
bind: 'localhost',
148+
timeout: 60000,
149+
logFile: '',
150+
env: 'test',
151+
disableEnvCheck: true,
152+
authVersion: 2,
153+
tlsMode: TlsMode.DISABLED,
154+
mtlsRequestCert: false,
155+
allowSelfSigned: true,
156+
};
157+
158+
const app = expressApp(invalidConfig as MasterExpressConfig);
159+
const testAgent = request.agent(app);
160+
161+
const response = await testAgent
162+
.post(`/api/${coin}/wallet/generate`)
163+
.set('Authorization', `Bearer ${accessToken}`)
164+
.send({
165+
label: 'test-wallet',
166+
});
167+
168+
response.status.should.equal(500);
169+
response.body.should.have.property('error');
170+
response.body.error.should.equal('Please configure enclaved express configs.');
171+
});
145172
});

src/__tests__/masterBitgoExpress/sendMany.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,42 @@ describe('POST /api/:coin/wallet/:walletId/sendmany', () => {
260260
walletGetNock.done();
261261
keychainGetNock.done();
262262
});
263+
264+
it('should fail when enclaved express client is not configured', async () => {
265+
// Create a config without enclaved express settings
266+
const invalidConfig: Partial<MasterExpressConfig> = {
267+
appMode: AppMode.MASTER_EXPRESS,
268+
port: 0,
269+
bind: 'localhost',
270+
timeout: 60000,
271+
logFile: '',
272+
env: 'test',
273+
disableEnvCheck: true,
274+
authVersion: 2,
275+
tlsMode: TlsMode.DISABLED,
276+
mtlsRequestCert: false,
277+
allowSelfSigned: true,
278+
};
279+
280+
const app = expressApp(invalidConfig as MasterExpressConfig);
281+
const testAgent = request.agent(app);
282+
283+
const response = await testAgent
284+
.post(`/api/${coin}/wallet/${walletId}/sendMany`)
285+
.set('Authorization', `Bearer ${accessToken}`)
286+
.send({
287+
recipients: [
288+
{
289+
address: 'tb1qtest1',
290+
amount: '100000',
291+
},
292+
],
293+
source: 'user',
294+
pubkey: 'xpub_user',
295+
});
296+
297+
response.status.should.equal(500);
298+
response.body.should.have.property('error');
299+
response.body.error.should.equal('Please configure enclaved express configs.');
300+
});
263301
});

src/masterBitgoExpress/generateWallet.ts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@ import {
88
WalletWithKeychains,
99
AddKeychainOptions,
1010
} from '@bitgo/sdk-core';
11-
import { createEnclavedExpressClient } from './enclavedExpressClient';
1211
import _ from 'lodash';
1312
import { MasterApiSpecRouteRequest } from './routers/masterApiSpec';
14-
import { isMasterExpressConfig } from '../types';
15-
import assert from 'assert';
1613

1714
/**
1815
* This route is used to generate a multisig wallet when enclaved express is enabled
@@ -23,17 +20,8 @@ export async function handleGenerateWalletOnPrem(
2320
const bitgo = req.bitgo;
2421
const baseCoin = bitgo.coin(req.params.coin);
2522

26-
assert(
27-
isMasterExpressConfig(req.config),
28-
'Expected req.config to be of type MasterExpressConfig',
29-
);
30-
31-
const enclavedExpressClient = createEnclavedExpressClient(req.config, req.params.coin);
32-
if (!enclavedExpressClient) {
33-
throw new Error(
34-
'Enclaved express client not configured - enclaved express features will be disabled',
35-
);
36-
}
23+
// The enclavedExpressClient is now available from the request
24+
const enclavedExpressClient = req.enclavedExpressClient;
3725

3826
const reqId = new RequestTracer();
3927

src/masterBitgoExpress/handleSendMany.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { RequestTracer, PrebuildTransactionOptions, Memo, KeyIndices } from '@bitgo/sdk-core';
2-
import { createEnclavedExpressClient } from './enclavedExpressClient';
32
import logger from '../logger';
43
import { MasterApiSpecRouteRequest } from './routers/masterApiSpec';
54
import { isMasterExpressConfig } from '../initConfig';
@@ -21,10 +20,7 @@ export async function handleSendMany(req: MasterApiSpecRouteRequest<'v1.wallet.s
2120
if (!isMasterExpressConfig(req.config)) {
2221
throw new Error('Configuration must be in master express mode');
2322
}
24-
const enclavedExpressClient = createEnclavedExpressClient(req.config, req.params.coin);
25-
if (!enclavedExpressClient) {
26-
throw new Error('Please configure enclaved express configs to sign the transactions.');
27-
}
23+
const enclavedExpressClient = req.enclavedExpressClient;
2824
const reqId = new RequestTracer();
2925
const bitgo = req.bitgo;
3026
const baseCoin = bitgo.coin(req.params.coin);
@@ -96,7 +92,7 @@ export async function handleSendMany(req: MasterApiSpecRouteRequest<'v1.wallet.s
9692
const err = e as Error;
9793
logger.error('transaction prebuild failed local validation:', err.message);
9894
logger.error('transaction prebuild:', JSON.stringify(txPrebuilt, null, 2));
99-
throw new Error(`Transaction prebuild failed local validation: ${err.message}`);
95+
throw new Error(`Transaction prebuild failed local validation: ${err.message}`);
10096
}
10197

10298
logger.debug('Tx prebuild: %s', JSON.stringify(txPrebuilt, null, 2));
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Request, Response, NextFunction } from 'express';
2+
import { isMasterExpressConfig } from '../types';
3+
import { createEnclavedExpressClient } from './enclavedExpressClient';
4+
import { BitGoRequest } from '../types/request';
5+
6+
/**
7+
* Middleware to validate master express configuration and enclaved express client
8+
*/
9+
export function validateMasterExpressConfig(req: Request, res: Response, next: NextFunction) {
10+
const bitgoReq = req as BitGoRequest;
11+
12+
// Validate master express config
13+
if (!isMasterExpressConfig(bitgoReq.config)) {
14+
return res.status(500).json({
15+
error: 'Invalid configuration',
16+
details: 'Expected req.config to be of type MasterExpressConfig',
17+
});
18+
}
19+
20+
// Validate enclaved express client
21+
const enclavedExpressClient = createEnclavedExpressClient(bitgoReq.config, bitgoReq.params?.coin);
22+
if (!enclavedExpressClient) {
23+
return res.status(500).json({
24+
error: 'Please configure enclaved express configs.',
25+
details: 'Enclaved express features will be disabled',
26+
});
27+
}
28+
29+
// Attach the client to the request for use in route handlers
30+
bitgoReq.enclavedExpressClient = enclavedExpressClient;
31+
next();
32+
}

src/masterBitgoExpress/routers/masterApiSpec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { MasterExpressConfig } from '../../initConfig';
1818
import { handleGenerateWalletOnPrem } from '../generateWallet';
1919
import { prepareBitGo, responseHandler } from '../../shared/middleware';
2020
import { handleSendMany } from '../handleSendMany';
21+
import { validateMasterExpressConfig } from '../middleware';
2122

2223
// Middleware functions
2324
export function parseBody(req: express.Request, res: express.Response, next: express.NextFunction) {
@@ -141,6 +142,7 @@ export function createMasterApiRouter(
141142
// Add middleware to all routes
142143
router.use(parseBody);
143144
router.use(prepareBitGo(cfg));
145+
router.use(validateMasterExpressConfig);
144146

145147
// Generate wallet endpoint handler
146148
router.post('v1.wallet.generate', [

src/types/request.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import express from 'express';
22
import { type BitGo } from 'bitgo';
33
import { Config } from '../types';
4+
import { EnclavedExpressClient } from '../masterBitgoExpress/enclavedExpressClient';
45

56
// Extended request type for BitGo Express
67
export interface BitGoRequest<T extends Config = Config> extends express.Request {
78
bitgo: BitGo;
89
config: T;
10+
enclavedExpressClient: EnclavedExpressClient;
911
}
1012

1113
export function isBitGoRequest<T extends Config>(req: express.Request): req is BitGoRequest<T> {

0 commit comments

Comments
 (0)