BackupDownload
Component for downloading encrypted wallet backups with security features
BackupDownload combines the Radix Button primitive with Bitcoin backup generation, providing secure encrypted wallet backup downloads with user guidance and safety instructions.
Basic Download
Required Download
Demo Note: This is a demonstration using test mnemonic data. In a real application, the backup would contain your actual encrypted wallet data.
Installation
npx bigblocks add backup-download
Import
import { BackupDownload } from 'bigblocks';
This component extends the Button primitive and inherits all its props.
Props
Prop | Type | Required | Default | Description |
---|---|---|---|---|
backup | BapMasterBackup | Yes | - | The backup data to download |
password | string | No | - | Password for encryption (if not already encrypted) |
onDownloaded | () => void | No | - | Callback when download is complete |
requireDownload | boolean | No | false | Whether download is required before proceeding |
className | string | No | - | Additional CSS classes |
Basic Usage
import { BackupDownload } from 'bigblocks';
export default function BackupExample() {
const backup = {
// BapMasterBackup data
idKey: 'L1...',
derivationScheme: 'master',
profiles: [],
bitcoin: {}
};
return (
<BackupDownload
backup={backup}
password="user-password"
onDownloaded={() => {
console.log('Backup downloaded successfully');
}}
/>
);
}
Advanced Usage
Required Download
import { BackupDownload } from 'bigblocks';
import { useState } from 'react';
export default function RequiredBackupFlow() {
const [downloadComplete, setDownloadComplete] = useState(false);
const backup = generateBackup(); // Your backup generation logic
return (
<div>
<h2>Step 2: Download Your Backup</h2>
<p>You must download your backup before continuing.</p>
<BackupDownload
backup={backup}
password="secure-password"
requireDownload={true}
onDownloaded={() => {
setDownloadComplete(true);
}}
/>
<button
disabled={!downloadComplete}
onClick={() => navigateToNextStep()}
>
Continue
</button>
</div>
);
}
With Custom Styling
import { BackupDownload } from 'bigblocks';
export default function StyledBackupDownload() {
const backup = getUserBackup();
return (
<BackupDownload
backup={backup}
password="user-password"
className="bg-orange-50 border-orange-200 rounded-lg p-4"
onDownloaded={() => {
toast.success('Backup saved successfully!');
}}
/>
);
}
In Registration Flow
import { BackupDownload } from 'bigblocks';
import { useAuth } from '@/hooks/useAuth';
export default function RegistrationBackupStep() {
const { backup, password } = useAuth();
const [downloaded, setDownloaded] = useState(false);
return (
<div className="max-w-md mx-auto">
<div className="mb-6">
<h2 className="text-2xl font-bold">Save Your Backup</h2>
<p className="text-gray-600">
This backup file is the only way to recover your account.
Download and store it safely.
</p>
</div>
<BackupDownload
backup={backup}
password={password}
requireDownload={true}
onDownloaded={() => {
setDownloaded(true);
analytics.track('backup_downloaded');
}}
/>
{downloaded && (
<div className="mt-4 p-3 bg-green-100 text-green-800 rounded">
✓ Backup downloaded successfully
</div>
)}
<div className="mt-6">
<button
className="w-full btn-primary"
disabled={!downloaded}
onClick={() => router.push('/dashboard')}
>
Complete Registration
</button>
</div>
</div>
);
}
Common Patterns
Backup Settings Page
import { BackupDownload } from 'bigblocks';
import { useWallet } from '@/hooks/useWallet';
export function BackupSettings() {
const { backup } = useWallet();
const [password, setPassword] = useState('');
const [showBackup, setShowBackup] = useState(false);
const handlePasswordSubmit = (e) => {
e.preventDefault();
// Validate password
setShowBackup(true);
};
return (
<div className="space-y-6">
<h3>Download Backup</h3>
{!showBackup ? (
<form onSubmit={handlePasswordSubmit}>
<input
type="password"
placeholder="Enter your password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<button type="submit">Continue</button>
</form>
) : (
<BackupDownload
backup={backup}
password={password}
onDownloaded={() => {
console.log('New backup downloaded');
setShowBackup(false);
setPassword('');
}}
/>
)}
</div>
);
}
With Progress Tracking
import { BackupDownload } from 'bigblocks';
export function BackupWithProgress() {
const [step, setStep] = useState(1);
const backup = generateBackup();
return (
<div>
<ProgressIndicator steps={3} current={step} />
{step === 1 && (
<div>
<h3>Create Password</h3>
<PasswordInput onSubmit={() => setStep(2)} />
</div>
)}
{step === 2 && (
<div>
<h3>Download Backup</h3>
<BackupDownload
backup={backup}
requireDownload={true}
onDownloaded={() => setStep(3)}
/>
</div>
)}
{step === 3 && (
<div>
<h3>Backup Complete!</h3>
<p>Your wallet is now safely backed up.</p>
</div>
)}
</div>
);
}
Error Handling
import { BackupDownload } from 'bigblocks';
export function BackupWithErrorHandling() {
const backup = getUserBackup();
const [error, setError] = useState(null);
if (!backup) {
return <div>No backup available</div>;
}
return (
<div>
{error && (
<div className="error-message">
{error}
</div>
)}
<BackupDownload
backup={backup}
onDownloaded={() => {
try {
// Additional validation or tracking
validateBackupDownload();
console.log('Backup downloaded successfully');
} catch (err) {
setError('Failed to validate backup download');
}
}}
/>
</div>
);
}
File Format
The downloaded backup file is encrypted and contains:
// Encrypted backup format (after decryption)
interface BapMasterBackup {
idKey: string; // Master private key
derivationScheme: string; // Key derivation scheme
profiles: ProfileInfo[]; // User profiles
bitcoin: { // Bitcoin-specific data
mnemonic?: string; // Optional seed phrase
network?: string; // Bitcoin network
};
}
The file is saved with a timestamp-based filename:
- Format:
bitcoin-backup-{timestamp}.txt
- Content: Base64 encoded encrypted data
Security Considerations
- Encryption: Backups are encrypted using AES-256-GCM
- Password: Never stored, only used for encryption
- Client-side: All encryption happens in the browser
- No Network: Download doesn't require network requests
- User Responsibility: Users must safely store their backups
Styling
The component uses Radix Themes and can be styled with:
/* Custom styling example */
.backup-download-container {
background: var(--orange-2);
border: 1px solid var(--orange-6);
border-radius: var(--radius-3);
padding: var(--space-4);
}
Best Practices
- Password Strength: Encourage strong passwords for encryption
- Multiple Copies: Advise users to make multiple backup copies
- Offline Storage: Recommend offline storage (USB, paper)
- Test Recovery: Suggest testing backup restoration
- Regular Updates: Remind users to update backups after profile changes
Troubleshooting
Download Not Working
- Check that backup data is valid BapMasterBackup format
- Ensure browser allows file downloads
- Verify password is provided if encryption is needed
File Not Encrypted
- Confirm password prop is provided
- Check that backup isn't already encrypted
- Verify encryption library is loaded
Callback Not Firing
- Ensure onDownloaded prop is a valid function
- Check browser console for errors
- Verify download completes successfully
Related Components
- BackupImport - Import backup files
- FileImport - General file import
- MemberExport - Export member backups
- QRCodeRenderer - QR code backups
API Reference
BapMasterBackup Type
The backup data structure expected by the component:
interface BapMasterBackup {
idKey: string;
derivationScheme: string;
profiles: Array<{
idKey: string;
name?: string;
// ... other profile data
}>;
bitcoin: {
mnemonic?: string;
network?: string;
};
}
File Generation
The component handles:
- Encryption of backup data (if password provided)
- Base64 encoding
- File blob creation
- Download trigger
- Cleanup
Notes for Improvement
Major Discrepancy: The prompt describes a much more feature-rich component than what's actually implemented. The actual component is simpler with:
- No variant prop (button vs card)
- No size options
- No preview functionality
- No progress tracking
- No error callback
- No custom filename support
- No instruction display options
- No backend integration
The actual implementation focuses solely on downloading an encrypted backup file with minimal UI.