Skip to content

Commit 96ec4c3

Browse files
fix(examples): use API to retrieve passcodeEncryptionCode in passphrase recovery
Replace manual activation code prompt with BitGo API authentication flow. Retrieve passcodeEncryptionCode via /wallet/{id}/passcoderecovery endpoint. Add coin registration, wallet retrieval, and key validation step. WCN-1331 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent bf178ef commit 96ec4c3

1 file changed

Lines changed: 74 additions & 13 deletions

File tree

examples/ts/btc/v1/wallet-passphrase-recovery.ts

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
/**
33
* Wallet Passphrase Recovery Script
44
*
5-
* This script takes box D information in the keycard and recovers the wallet passphrase.
5+
* This script recovers the wallet passphrase for V1 Wallets by authenticating with BitGo,
6+
* retrieving the passcodeEncryptionCode from the API, and using it to decrypt Box D of the keycard.
67
*
78
* The script will prompt for:
89
* - Environment (test/prod)
9-
* - Activation code
10+
* - BitGo credentials (username, password, OTP)
11+
* - Wallet ID
1012
* - Encrypted wallet passphrase from Box D of keycard
1113
*
1214
* You need to install node and BitGoJS SDK to run this script.
@@ -23,6 +25,7 @@
2325
*/
2426

2527
import { BitGoAPI } from '@bitgo/sdk-api';
28+
import { Btc, Tbtc } from '@bitgo/sdk-coin-btc';
2629
import * as readline from 'readline';
2730

2831
// Create readline interface for user input
@@ -46,16 +49,24 @@ async function main(): Promise<void> {
4649
console.log('====================================\n');
4750

4851
// Get environment setting
49-
const envInput = await askQuestion(
50-
'Enter environment (test/prod) [default: test]: ',
51-
);
52+
const envInput = await askQuestion('Enter environment (test/prod) [default: test]: ');
5253
const env = envInput.toLowerCase() === 'prod' ? 'prod' : 'test';
5354

5455
// Initialize BitGo
5556
const bitgo = new BitGoAPI({
5657
env: env,
5758
});
5859

60+
// Register appropriate coin based on environment
61+
const coinType = env === 'prod' ? 'btc' : 'tbtc';
62+
if (coinType === 'btc') {
63+
bitgo.register('btc', Btc.createInstance);
64+
console.log('Using production environment with BTC');
65+
} else {
66+
bitgo.register('tbtc', Tbtc.createInstance);
67+
console.log('Using test environment with TBTC');
68+
}
69+
5970
// Get login credentials from stdin
6071
const username = await askQuestion('\nEnter your BitGo username: ');
6172
const password = await askQuestion('Enter your BitGo password: ');
@@ -92,21 +103,71 @@ async function main(): Promise<void> {
92103
await bitgo.unlock({ otp: unlockOtp });
93104
console.log('Session unlocked successfully.');
94105

95-
// Get activation code
96-
const activationCode = await askQuestion('Enter activation code: ');
106+
// Get wallet ID from user
107+
const walletId = await askQuestion('\nEnter your wallet ID: ');
108+
109+
// Retrieve wallet instance
110+
console.log(`Retrieving wallet information for ID: ${walletId}...`);
111+
const walletInstance = await bitgo.wallets().get({ id: walletId });
112+
113+
if (!walletInstance) {
114+
throw new Error('Wallet not found');
115+
}
116+
117+
console.log(`Wallet found: ${walletInstance.label()}`);
118+
119+
// Retrieve recovery info from BitGo
120+
const path = bitgo.url(`/wallet/${walletInstance.id()}/passcoderecovery`);
121+
console.log(`\nFetching recovery info from ${path.toString()}`);
122+
123+
const recoveryResponse = await bitgo.post(path.toString()).result();
124+
125+
console.log('Recovery information retrieved successfully.');
126+
127+
// Extract passcode encryption code
128+
if (!recoveryResponse.recoveryInfo || !recoveryResponse.recoveryInfo.passcodeEncryptionCode) {
129+
throw new Error('Recovery info not found or missing passcode encryption code');
130+
}
131+
132+
const { passcodeEncryptionCode, encryptedXprv } = recoveryResponse.recoveryInfo;
97133

98134
// Get encrypted wallet passphrase from Box D
99-
const encryptedWalletPassphrase = await askQuestion(
100-
'Enter encrypted wallet passphrase from Box D: ',
101-
);
135+
const encryptedWalletPassphrase = await askQuestion('\nEnter encrypted wallet passphrase from Box D: ');
136+
137+
if (!encryptedWalletPassphrase) {
138+
throw new Error('Encrypted wallet passphrase is required');
139+
}
140+
141+
console.log('\nDecrypting wallet passphrase using recovery information...');
102142

103143
// Decrypt the wallet passphrase
104-
const walletPassphrase = bitgo.decrypt({
144+
const walletPassphrase = await bitgo.decrypt({
105145
input: encryptedWalletPassphrase,
106-
password: activationCode,
146+
password: passcodeEncryptionCode,
107147
});
108148

109-
console.log(`\n✅ SUCCESS: the decrypted passphrase is: ${walletPassphrase}`);
149+
console.log('Successfully decrypted the wallet passphrase.');
150+
151+
// Validate the decrypted passphrase against the wallet's encrypted xprv
152+
console.log('\nValidating the decrypted passphrase against wallet keys...');
153+
154+
const coin = bitgo.coin(coinType);
155+
156+
try {
157+
coin.assertIsValidKey({
158+
encryptedPrv: encryptedXprv,
159+
walletPassphrase: walletPassphrase,
160+
});
161+
162+
console.log(`\n✅ SUCCESS: the decrypted passphrase is: ${walletPassphrase}`);
163+
console.log(`
164+
Please store this passphrase securely as it provides access to your wallet.
165+
Do not share this passphrase with anyone.`);
166+
} catch (error) {
167+
console.error('\n❌ VALIDATION FAILED: The recovered passphrase could not validate the wallet key.');
168+
console.error('Please check that you entered the correct encrypted passphrase from Box D.');
169+
console.error(`Error details: ${error.message}`);
170+
}
110171
} catch (error) {
111172
console.error(`\nError: ${error.message}`);
112173
if (error.status) {

0 commit comments

Comments
 (0)