Skip to content

Commit a99c309

Browse files
feat(express): decouple signer node data update from init wallet
few more Ticket: BTC-1866
1 parent 1a9ffdf commit a99c309

File tree

4 files changed

+64
-67
lines changed

4 files changed

+64
-67
lines changed

modules/express/src/lightning/codecs.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,8 @@ export const InitLightningWalletRequest = t.intersection(
3636
[
3737
t.strict({
3838
passphrase: t.string,
39-
signerHost: t.string,
40-
signerTlsCert: t.string,
4139
}),
4240
t.partial({
43-
signerTlsKey: t.string,
4441
expressHost: t.string,
4542
}),
4643
],
@@ -49,11 +46,15 @@ export const InitLightningWalletRequest = t.intersection(
4946

5047
export type InitLightningWalletRequest = t.TypeOf<typeof InitLightningWalletRequest>;
5148

52-
export const CreateSignerMacaroonRequest = t.strict(
53-
{
54-
passphrase: t.string,
55-
watchOnlyIp: t.string,
56-
},
49+
export const CreateSignerMacaroonRequest = t.intersection(
50+
[
51+
t.strict({
52+
passphrase: t.string,
53+
}),
54+
t.partial({
55+
watchOnlyIp: t.string,
56+
}),
57+
],
5758
'CreateSignerMacaroonRequest'
5859
);
5960

modules/express/src/lightning/lightningSignerRoutes.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ import { ApiResponseError } from '../errors';
2525
type Decrypt = (params: { input: string; password: string }) => string;
2626

2727
async function createSignerMacaroon(
28-
watchOnlyIp: string,
28+
lndSignerClient: LndSignerClient,
2929
header: { adminMacaroonHex: string },
30-
lndSignerClient: LndSignerClient
31-
) {
30+
watchOnlyIp?: string
31+
): Promise<string> {
3232
const { macaroon } = await lndSignerClient.bakeMacaroon({ permissions: signerMacaroonPermissions }, header);
33-
const macaroonBase64 = addIPCaveatToMacaroon(Buffer.from(macaroon, 'hex').toString('base64'), watchOnlyIp);
34-
return Buffer.from(macaroonBase64, 'base64').toString('hex');
33+
const macaroonBase64 = watchOnlyIp
34+
? addIPCaveatToMacaroon(Buffer.from(macaroon, 'hex').toString('base64'), watchOnlyIp)
35+
: undefined;
36+
return macaroonBase64 ? Buffer.from(macaroonBase64, 'base64').toString('hex') : macaroon;
3537
}
3638

3739
function getSignerRootKey(
@@ -71,7 +73,7 @@ export async function handleInitLightningWallet(req: express.Request): Promise<u
7173
throw new ApiResponseError(`Invalid wallet id: ${walletId}`, 400);
7274
}
7375

74-
const { passphrase, signerTlsKey, signerTlsCert, signerHost, expressHost } = decodeOrElse(
76+
const { passphrase, expressHost } = decodeOrElse(
7577
InitLightningWalletRequest.name,
7678
InitLightningWalletRequest,
7779
req.body,
@@ -104,15 +106,11 @@ export async function handleInitLightningWallet(req: express.Request): Promise<u
104106
input: expressHost && !!isIP(expressHost) ? addIPCaveatToMacaroon(adminMacaroon, expressHost) : adminMacaroon,
105107
});
106108
const watchOnlyAccounts = createWatchOnly(signerRootKey, network);
107-
const encryptedSignerTlsKey = signerTlsKey ? bitgo.encrypt({ password: passphrase, input: signerTlsKey }) : undefined;
108109

109110
return await lightningWallet.updateWalletCoinSpecific(
110111
{
111112
encryptedSignerAdminMacaroon,
112-
signerHost,
113-
signerTlsCert,
114113
watchOnlyAccounts,
115-
...(encryptedSignerTlsKey && { encryptedSignerTlsKey }),
116114
},
117115
passphrase
118116
);
@@ -143,7 +141,7 @@ export async function handleCreateSignerMacaroon(req: express.Request): Promise<
143141
}
144142
);
145143

146-
if (!isIP(watchOnlyIp)) {
144+
if (watchOnlyIp !== undefined && !isIP(watchOnlyIp)) {
147145
throw new ApiResponseError(`Invalid IP address: ${watchOnlyIp}`, 400);
148146
}
149147

@@ -164,9 +162,9 @@ export async function handleCreateSignerMacaroon(req: express.Request): Promise<
164162
const { userAuthKey } = await lightningWallet.getLightningAuthKeychains();
165163

166164
const signerMacaroon = await createSignerMacaroon(
167-
watchOnlyIp,
165+
lndSignerClient,
168166
{ adminMacaroonHex: Buffer.from(adminMacaroon, 'base64').toString('hex') },
169-
lndSignerClient
167+
watchOnlyIp
170168
);
171169

172170
const userAuthXprv = bitgo.decrypt({

modules/express/test/unit/clientRoutes/lightning/lightningSignerFixture.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@ export const apiData = {
22
initWalletRequestBody: {
33
passphrase: 'password123',
44
expressHost: '127.0.0.1',
5-
signerHost: '127.0.0.1',
6-
signerTlsCert:
7-
'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNQRENDQWVLZ0F3SUJBZ0lSQU02TEFoaGxOMGo4ZlhxV2dLTWdENmN3Q2dZSUtvWkl6ajBFQXdJd09ERWYKTUIwR0ExVUVDaE1XYkc1a0lHRjFkRzluWlc1bGNtRjBaV1FnWTJWeWRERVZNQk1HQTFVRUF4TU1aV1UxTVdZeApOREV4TUdVMk1CNFhEVEkwTURneE9ERXlNVE14TWxvWERUSTFNVEF4TXpFeU1UTXhNbG93T0RFZk1CMEdBMVVFCkNoTVdiRzVrSUdGMWRHOW5aVzVsY21GMFpXUWdZMlZ5ZERFVk1CTUdBMVVFQXhNTVpXVTFNV1l4TkRFeE1HVTIKTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFclA0d2NXWFEwUWFFazhsVFNVTXBCa1d3ditFbQpxNTNyOWVSeVJUOTRkZGdVR0tTMFlRK0liZzFseVBRU3hiN0dXYloyWG9GUFdiK1VOM0lFMVlMQ2thT0J6RENCCnlUQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0V3WURWUjBsQkF3d0NnWUlLd1lCQlFVSEF3RXdEd1lEVlIwVEFRSC8KQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVb3JmUkNVQytmaUNjZlE4cEhEUTFWaE1uMXBBd2NnWURWUjBSQkdzdwphWUlNWldVMU1XWXhOREV4TUdVMmdnbHNiMk5oYkdodmMzU0NDbk5wWjI1bGNtNXZaR1dDQ1d4dlkyRnNhRzl6CmRJSUVkVzVwZUlJS2RXNXBlSEJoWTJ0bGRJSUhZblZtWTI5dWJvY0Vmd0FBQVljUUFBQUFBQUFBQUFBQUFBQUEKQUFBQUFZY0VyQlFBQWpBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlFQXJuQ0xRTlgzeDZ1NjhIM2xCOG9wOUFKaApBd2RrUjhXOXNSaUZnZDJKM2tZQ0lHczFOVGM0T0toRzByNzVHUWpXb2x0SkJyOUtjWWVyR1V3aklCaCtvZ1h0Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K',
8-
signerTlsKey:
9-
'LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUFFamQ0Qng3M3VPYllGSW42VlZpZTJmeG9lbXVYZFBob2FkS2JscHpnaTBvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFclA0d2NXWFEwUWFFazhsVFNVTXBCa1d3ditFbXE1M3I5ZVJ5UlQ5NGRkZ1VHS1MwWVErSQpiZzFseVBRU3hiN0dXYloyWG9GUFdiK1VOM0lFMVlMQ2tRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=',
105
},
116
signerMacaroonRequestBody: {
127
passphrase: 'password123',

modules/express/test/unit/clientRoutes/lightning/lightningSignerRoutes.ts

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe('Lightning signer routes', () => {
6363
bitgo: bitgo,
6464
body: includingOptionalFields
6565
? apiData.initWalletRequestBody
66-
: { ...apiData.initWalletRequestBody, signerTlsKey: undefined },
66+
: { ...apiData.initWalletRequestBody, expressHost: undefined },
6767
params: {
6868
coin: 'tlnbtc',
6969
id: 'fakeid',
@@ -84,6 +84,49 @@ describe('Lightning signer routes', () => {
8484
});
8585
}
8686

87+
for (const includingOptionalFields of [true, false]) {
88+
it(`should create signer macaroon ${includingOptionalFields ? 'with' : 'without'} optional fields`, async () => {
89+
const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(JSON.stringify(lightningSignerConfigs));
90+
const wpWalletnock = nock(bgUrl).get(`/api/v2/tlnbtc/wallet/${apiData.wallet.id}`).reply(200, apiData.wallet);
91+
92+
const wpKeychainNocks = [
93+
nock(bgUrl).get(`/api/v2/tlnbtc/key/${apiData.userAuthKey.id}`).reply(200, apiData.userAuthKey),
94+
nock(bgUrl).get(`/api/v2/tlnbtc/key/${apiData.nodeAuthKey.id}`).reply(200, apiData.nodeAuthKey),
95+
nock(bgUrl).get(`/api/v2/tlnbtc/key/${apiData.userAuthKey.id}`).reply(200, apiData.userAuthKey),
96+
nock(bgUrl).get(`/api/v2/tlnbtc/key/${apiData.nodeAuthKey.id}`).reply(200, apiData.nodeAuthKey),
97+
];
98+
99+
const signerMacaroon = nock(lightningSignerConfigs.fakeid.url)
100+
.post(`/v1/macaroon`)
101+
.reply(200, signerApiData.bakeMacaroon);
102+
103+
const wpWalletUpdateNock = nock(bgUrl).put(`/api/v2/tlnbtc/wallet/${apiData.wallet.id}`).reply(200);
104+
105+
const req = {
106+
bitgo: bitgo,
107+
body: includingOptionalFields
108+
? apiData.signerMacaroonRequestBody
109+
: { ...apiData.signerMacaroonRequestBody, watchOnlyIp: undefined },
110+
params: {
111+
coin: 'tlnbtc',
112+
id: 'fakeid',
113+
},
114+
config: {
115+
lightningSignerFileSystemPath: 'lightningSignerFileSystemPath',
116+
},
117+
} as unknown as express.Request;
118+
119+
await handleCreateSignerMacaroon(req);
120+
121+
wpWalletUpdateNock.done();
122+
signerMacaroon.done();
123+
wpKeychainNocks.forEach((s) => s.done());
124+
wpWalletnock.done();
125+
readFileStub.calledOnceWith('lightningSignerFileSystemPath').should.be.true();
126+
readFileStub.restore();
127+
});
128+
}
129+
87130
it('should get signer wallet state', async () => {
88131
const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(JSON.stringify(lightningSignerConfigs));
89132
const walletStateNock = nock(lightningSignerConfigs.fakeid.url)
@@ -92,7 +135,6 @@ describe('Lightning signer routes', () => {
92135

93136
const req = {
94137
bitgo: bitgo,
95-
body: apiData.signerMacaroonRequestBody,
96138
params: {
97139
coin: 'tlnbtc',
98140
id: apiData.wallet.id,
@@ -109,45 +151,6 @@ describe('Lightning signer routes', () => {
109151
readFileStub.restore();
110152
});
111153

112-
it('should create signer macaroon', async () => {
113-
const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(JSON.stringify(lightningSignerConfigs));
114-
const wpWalletnock = nock(bgUrl).get(`/api/v2/tlnbtc/wallet/${apiData.wallet.id}`).reply(200, apiData.wallet);
115-
116-
const wpKeychainNocks = [
117-
nock(bgUrl).get(`/api/v2/tlnbtc/key/${apiData.userAuthKey.id}`).reply(200, apiData.userAuthKey),
118-
nock(bgUrl).get(`/api/v2/tlnbtc/key/${apiData.nodeAuthKey.id}`).reply(200, apiData.nodeAuthKey),
119-
nock(bgUrl).get(`/api/v2/tlnbtc/key/${apiData.userAuthKey.id}`).reply(200, apiData.userAuthKey),
120-
nock(bgUrl).get(`/api/v2/tlnbtc/key/${apiData.nodeAuthKey.id}`).reply(200, apiData.nodeAuthKey),
121-
];
122-
123-
const signerMacaroon = nock(lightningSignerConfigs.fakeid.url)
124-
.post(`/v1/macaroon`)
125-
.reply(200, signerApiData.bakeMacaroon);
126-
127-
const wpWalletUpdateNock = nock(bgUrl).put(`/api/v2/tlnbtc/wallet/${apiData.wallet.id}`).reply(200);
128-
129-
const req = {
130-
bitgo: bitgo,
131-
body: apiData.signerMacaroonRequestBody,
132-
params: {
133-
coin: 'tlnbtc',
134-
id: 'fakeid',
135-
},
136-
config: {
137-
lightningSignerFileSystemPath: 'lightningSignerFileSystemPath',
138-
},
139-
} as unknown as express.Request;
140-
141-
await handleCreateSignerMacaroon(req);
142-
143-
wpWalletUpdateNock.done();
144-
signerMacaroon.done();
145-
wpKeychainNocks.forEach((s) => s.done());
146-
wpWalletnock.done();
147-
readFileStub.calledOnceWith('lightningSignerFileSystemPath').should.be.true();
148-
readFileStub.restore();
149-
});
150-
151154
it('should unlock lightning wallet', async () => {
152155
const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(JSON.stringify(lightningSignerConfigs));
153156

0 commit comments

Comments
 (0)