Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 99 additions & 14 deletions examples/ts/btc/v1/wallet-passphrase-recovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
/**
* Wallet Passphrase Recovery Script
*
* This script takes box D information in the keycard and recovers the wallet passphrase.
* This script recovers the wallet passphrase for V1 Wallets by authenticating with BitGo,
* retrieving the passcodeEncryptionCode from the API, and using it to decrypt Box D of the keycard.
*
* The script will prompt for:
* - Environment (test/prod)
* - Activation code
* - BitGo credentials (username, password, OTP)
* - Wallet ID
* - Encrypted wallet passphrase from Box D of keycard
*
*
* You need to install node and BitGoJS SDK to run this script.
*
*
* To install node, you can follow the instructions here: https://nodejs.org/en/download
*
* To install BitGoJS SDK, you can use the following command:
Expand All @@ -23,6 +25,7 @@
*/

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

// Create readline interface for user input
Expand All @@ -46,31 +49,113 @@ async function main(): Promise<void> {
console.log('====================================\n');

// Get environment setting
const envInput = await askQuestion(
'Enter environment (test/prod) [default: test]: ',
);
const envInput = await askQuestion('Enter environment (test/prod) [default: test]: ');
const env = envInput.toLowerCase() === 'prod' ? 'prod' : 'test';

// Initialize BitGo
const bitgo = new BitGoAPI({
env: env,
});

// Get activation code
const activationCode = await askQuestion('Enter activation code: ');
// Register appropriate coin based on environment
const coinType = env === 'prod' ? 'btc' : 'tbtc';
if (coinType === 'btc') {
bitgo.register('btc', Btc.createInstance);
console.log('Using production environment with BTC');
} else {
bitgo.register('tbtc', Tbtc.createInstance);
console.log('Using test environment with TBTC');
}

// Get login credentials from stdin
const username = await askQuestion('\nEnter your BitGo username: ');
const password = await askQuestion('Enter your BitGo password: ');
const loginOtp = await askQuestion('Enter your OTP code for login: ');

console.log('\nAuthenticating with BitGo...');

// Authenticate with BitGo
await bitgo.authenticate({
username,
password,
otp: loginOtp,
});

console.log('Authentication successful.');

// Get a fresh OTP for session unlock
const unlockOtp = await askQuestion('\nEnter a new OTP code for session unlock: ');

// Unlock session
console.log('Unlocking session...');
await bitgo.unlock({ otp: unlockOtp });
console.log('Session unlocked successfully.');

// Get wallet ID from user
const walletId = await askQuestion('\nEnter your wallet ID: ');

// Retrieve wallet instance
console.log(`Retrieving wallet information for ID: ${walletId}...`);
const walletInstance = await bitgo.wallets().get({ id: walletId });

if (!walletInstance) {
throw new Error('Wallet not found');
}

console.log(`Wallet found: ${walletInstance.label()}`);

// Retrieve recovery info from BitGo
const path = bitgo.url(`/wallet/${walletInstance.id()}/passcoderecovery`);
console.log(`\nFetching recovery info from ${path.toString()}`);

const recoveryResponse = await bitgo.post(path.toString()).result();

console.log('Recovery information retrieved successfully.');

// Extract passcode encryption code
if (!recoveryResponse.recoveryInfo || !recoveryResponse.recoveryInfo.passcodeEncryptionCode) {
throw new Error('Recovery info not found or missing passcode encryption code');
}

const { passcodeEncryptionCode, encryptedXprv } = recoveryResponse.recoveryInfo;

// Get encrypted wallet passphrase from Box D
const encryptedWalletPassphrase = await askQuestion(
'Enter encrypted wallet passphrase from Box D: ',
);
const encryptedWalletPassphrase = await askQuestion('\nEnter encrypted wallet passphrase from Box D: ');

if (!encryptedWalletPassphrase) {
throw new Error('Encrypted wallet passphrase is required');
}

console.log('\nDecrypting wallet passphrase using recovery information...');

// Decrypt the wallet passphrase
const walletPassphrase = bitgo.decrypt({
input: encryptedWalletPassphrase,
password: activationCode,
password: passcodeEncryptionCode,
});

console.log(`\n✅ SUCCESS: the decrypted passphrase is: ${walletPassphrase}`);
console.log('Successfully decrypted the wallet passphrase.');

// Validate the decrypted passphrase against the wallet's encrypted xprv
console.log('\nValidating the decrypted passphrase against wallet keys...');

const coin = bitgo.coin(coinType);

try {
coin.assertIsValidKey({
encryptedPrv: encryptedXprv,
walletPassphrase: walletPassphrase,
});

console.log(`\n✅ SUCCESS: the decrypted passphrase is: ${walletPassphrase}`);
console.log(`
Please store this passphrase securely as it provides access to your wallet.
Do not share this passphrase with anyone.`);
} catch (error) {
console.error('\n❌ VALIDATION FAILED: The recovered passphrase could not validate the wallet key.');
console.error('Please check that you entered the correct encrypted passphrase from Box D.');
console.error(`Error details: ${error.message}`);
}
} catch (error) {
console.error(`\nError: ${error.message}`);
if (error.status) {
Expand Down