Skip to content

Commit b16c67b

Browse files
authored
Merge pull request #5938 from BitGo/FR-460-express-change-wallet-pw
feat(express): add support to change keychain password
2 parents 3ec760f + 8cef8e1 commit b16c67b

File tree

3 files changed

+121
-21
lines changed

3 files changed

+121
-21
lines changed

commitlint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module.exports = {
2020
'BOS-',
2121
'BT-',
2222
'BTC-',
23+
'CAAS-',
2324
'CE-',
2425
'CEN-',
2526
'CLEX-',

modules/express/src/clientRoutes.ts

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,33 @@
22
* @prettier
33
*/
44
import {
5-
EddsaUtils,
6-
EcdsaUtils,
7-
EcdsaMPCv2Utils,
8-
CustomGShareGeneratingFunction,
9-
CustomRShareGeneratingFunction,
10-
UnsupportedCoinError,
11-
GShare,
12-
SignShare,
13-
CustomCommitmentGeneratingFunction,
145
CommitmentShareRecord,
15-
EncryptedSignerShareRecord,
16-
CustomPaillierModulusGetterFunction,
6+
CreateNetworkConnectionParams,
7+
CustomCommitmentGeneratingFunction,
8+
CustomGShareGeneratingFunction,
179
CustomKShareGeneratingFunction,
10+
CustomMPCv2SigningRound1GeneratingFunction,
11+
CustomMPCv2SigningRound2GeneratingFunction,
12+
CustomMPCv2SigningRound3GeneratingFunction,
1813
CustomMuDeltaShareGeneratingFunction,
14+
CustomPaillierModulusGetterFunction,
15+
CustomRShareGeneratingFunction,
1916
CustomSShareGeneratingFunction,
17+
EcdsaMPCv2Utils,
18+
EcdsaUtils,
19+
EddsaUtils,
20+
EncryptedSignerShareRecord,
21+
encryptRsaWithAesGcm,
22+
GetNetworkPartnersResponse,
23+
GShare,
24+
MPCType,
25+
ShareType,
26+
SignShare,
27+
SShare,
2028
TssEcdsaStep1ReturnMessage,
2129
TssEcdsaStep2ReturnMessage,
22-
SShare,
23-
ShareType,
24-
MPCType,
25-
CreateNetworkConnectionParams,
26-
GetNetworkPartnersResponse,
27-
encryptRsaWithAesGcm,
30+
UnsupportedCoinError,
2831
Wallet,
29-
CustomMPCv2SigningRound1GeneratingFunction,
30-
CustomMPCv2SigningRound2GeneratingFunction,
31-
CustomMPCv2SigningRound3GeneratingFunction,
3232
} from '@bitgo/sdk-core';
3333
import { BitGo, BitGoOptions, Coin, CustomSigningFunction, SignedTransaction, SignedTransactionRequest } from 'bitgo';
3434
import * as bodyParser from 'body-parser';
@@ -965,7 +965,7 @@ async function handleV2SendMany(req: express.Request) {
965965
}
966966

967967
/**
968-
* Routes payload meant for prebuildAndSignTransaction() in sdk-core which
968+
* payload meant for prebuildAndSignTransaction() in sdk-core which
969969
* validates the payload and makes the appropriate request to WP to
970970
* build, sign, and send a tx.
971971
* - sends request to Platform to build the transaction
@@ -1025,6 +1025,43 @@ async function handleWalletUpdate(req: express.Request): Promise<unknown> {
10251025
return await bitgo.put(wallet.url()).send(req.body).result();
10261026
}
10271027

1028+
/**
1029+
* Changes a keychain's passphrase, re-encrypting the key to a new password
1030+
* @param req
1031+
*/
1032+
export async function handleKeychainChangePassword(req: express.Request): Promise<unknown> {
1033+
const { oldPassword, newPassword, otp } = req.body;
1034+
if (!oldPassword || !newPassword) {
1035+
throw new ApiResponseError('Missing 1 or more required fields: [oldPassword, newPassword]', 400);
1036+
}
1037+
const reqId = new RequestTracer();
1038+
1039+
const bitgo = req.bitgo;
1040+
const coin = bitgo.coin(req.params.coin);
1041+
1042+
if (otp) {
1043+
await bitgo.unlock({ otp });
1044+
}
1045+
1046+
const keychain = await coin.keychains().get({
1047+
id: req.params.id,
1048+
reqId,
1049+
});
1050+
if (!keychain) {
1051+
throw new ApiResponseError(`Keychain ${req.params.id} not found`, 404);
1052+
}
1053+
1054+
const updatedKeychain = coin.keychains().updateSingleKeychainPassword({
1055+
keychain,
1056+
oldPassword,
1057+
newPassword,
1058+
});
1059+
1060+
return bitgo.put(coin.url(`/key/${updatedKeychain.id}`)).send({
1061+
encryptedPrv: updatedKeychain.encryptedPrv,
1062+
});
1063+
}
1064+
10281065
/**
10291066
* handle any other API call
10301067
* @param req
@@ -1577,6 +1614,14 @@ export function setupAPIRoutes(app: express.Application, config: Config): void {
15771614

15781615
app.put('/express/api/v2/:coin/wallet/:id', parseBody, prepareBitGo(config), promiseWrapper(handleWalletUpdate));
15791616

1617+
// change wallet passphrase
1618+
app.post(
1619+
'/api/v2/:coin/keychain/:id/changepassword',
1620+
parseBody,
1621+
prepareBitGo(config),
1622+
promiseWrapper(handleKeychainChangePassword)
1623+
);
1624+
15801625
// create address
15811626
app.post('/api/v2/:coin/wallet/:id/address', parseBody, prepareBitGo(config), promiseWrapper(handleV2CreateAddress));
15821627

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import * as sinon from 'sinon';
2+
3+
import 'should-http';
4+
import 'should-sinon';
5+
import '../../lib/asserts';
6+
7+
import * as express from 'express';
8+
9+
import { handleKeychainChangePassword } from '../../../src/clientRoutes';
10+
11+
import { BitGo } from 'bitgo';
12+
13+
describe('Change Wallet Password', function () {
14+
it('should change wallet password', async function () {
15+
const keychainBaseCoinStub = {
16+
keychains: () => ({ updateSingleKeychainPassword: () => Promise.resolve({ result: 'stubbed' }) }),
17+
};
18+
const keychainStub = {
19+
baseCoin: keychainBaseCoinStub,
20+
};
21+
22+
const coinStub = {
23+
keychains: () => ({
24+
get: () => Promise.resolve(keychainStub),
25+
updateSingleKeychainPassword: () => ({ result: 'stubbed' }),
26+
}),
27+
url: () => 'url',
28+
};
29+
30+
const stubBitgo = sinon.createStubInstance(BitGo as any, {
31+
coin: coinStub,
32+
});
33+
stubBitgo['put'] = sinon.stub().returns({
34+
send: () => ({
35+
result: '200 OK',
36+
}),
37+
});
38+
39+
const mockRequest = {
40+
bitgo: stubBitgo,
41+
params: {
42+
coin: 'talgo',
43+
id: '23423423423423',
44+
},
45+
body: {
46+
oldPassword: 'oldPasswordString',
47+
newPassword: 'newPasswordString',
48+
},
49+
};
50+
51+
const result = await handleKeychainChangePassword(mockRequest as express.Request & typeof mockRequest);
52+
({ result: '200 OK' }).should.be.eql(result);
53+
});
54+
});

0 commit comments

Comments
 (0)