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.
2325 */
2426
2527import { BitGoAPI } from '@bitgo/sdk-api' ;
28+ import { Btc , Tbtc } from '@bitgo/sdk-coin-btc' ;
2629import * 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