-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmockKeyProviderServer.ts
More file actions
97 lines (82 loc) · 3.05 KB
/
mockKeyProviderServer.ts
File metadata and controls
97 lines (82 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import * as http from 'http';
import * as path from 'path';
import express from 'express';
import { BitGoAPI } from '@bitgo-beta/sdk-api';
import { Hteth } from '@bitgo-beta/sdk-coin-eth';
import { Tbtc } from '@bitgo-beta/sdk-coin-btc';
import { listen, close } from './servers';
function loadKeyProviderFixture(name: string): Record<string, unknown> {
return require(`${path.resolve(__dirname, '../fixtures/keyProvider')}/${name}.json`);
}
export interface MockKeyProviderCall {
method: string;
path: string;
body: unknown;
}
export interface MockKeyProviderServer {
port: number;
calls: MockKeyProviderCall[];
close(): Promise<void>;
}
interface StoredKey {
prv: string;
source: string;
type: string;
}
/**
* @returns BitGo Instance with coins registered
*/
function createBitgoInstance(): BitGoAPI {
const instance = new BitGoAPI({ env: 'test' });
instance.register('hteth', Hteth.createInstance);
instance.register('tbtc', Tbtc.createInstance);
return instance;
}
function generateKeypair(coin: string): { pub: string; prv: string } {
const keychain = createBitgoInstance().coin(coin).keychains().create();
if (!keychain.pub || !keychain.prv)
throw new Error(`Failed to generate keypair for coin: ${coin}`);
return { pub: keychain.pub, prv: keychain.prv };
}
export async function startMockKeyProviderServer(): Promise<MockKeyProviderServer> {
const calls: MockKeyProviderCall[] = [];
const keyStore = new Map<string, StoredKey>();
const app = express();
app.use(express.json());
app.use((req, _res, next) => {
calls.push({ method: req.method, path: req.path, body: req.body });
next();
});
/** External signing mode — key provider generates the key */
app.post('/key/generate', (req, res) => {
const { coin, source, type } = req.body;
const { pub, prv } = generateKeypair(coin);
keyStore.set(pub, { prv, source, type });
res.json({ pub, coin, source, type });
});
/** Local signing mode — AWM generates the key and sends it here for storage */
app.post('/key', (req, res) => {
const { pub, prv, coin, source, type } = req.body;
keyStore.set(pub, { prv, source, type });
res.json({ pub, coin, source, type });
});
/** Local signing mode — AWM retrieves the stored key to sign locally */
app.get('/key/:pub', (req, res) => {
const entry = keyStore.get(req.params.pub);
if (!entry) {
res.status(404).json({ message: `Key not found: ${req.params.pub}` });
return;
}
res.json({ pub: req.params.pub, ...entry });
});
/** External signing mode — key provider signs the payload, returns signed PSBT or ETH sig.
* ETH signablePayload starts with 0x (operation hash), BTC is a PSBT hex. */
app.post('/sign', (req, res) => {
const { signablePayload } = req.body;
const isEth = typeof signablePayload === 'string' && signablePayload.startsWith('0x');
res.json(loadKeyProviderFixture(isEth ? 'sign.eth' : 'sign'));
});
const server = http.createServer(app);
const port = await listen(server);
return { port, calls, close: () => close(server) };
}