Skip to main content

sol_safekey/
interactive.rs

1//! Interactive Menu Module
2//!
3//! Provides a simple interactive interface - no need to memorize commands
4//! 提供简单的交互式界面 - 无需记住命令
5
6use std::io::{self, Write};
7use colored::*;
8use solana_sdk::signature::Keypair;
9use solana_sdk::signer::Signer;
10
11use crate::KeyManager;
12
13/// Language selection
14#[derive(Clone, Copy, PartialEq)]
15pub enum Language {
16    English,
17    Chinese,
18}
19
20/// Text strings for bilingual UI
21struct Texts {
22    // Main menu
23    title: &'static str,
24    core_functions: &'static str,
25    create_plain: &'static str,
26    create_encrypted: &'static str,
27    decrypt: &'static str,
28    exit: &'static str,
29    select_option: &'static str,
30    goodbye: &'static str,
31    invalid_option: &'static str,
32    continue_use: &'static str,
33
34    // Plain key creation
35    create_plain_title: &'static str,
36    keypair_generated: &'static str,
37    public_key: &'static str,
38    private_key: &'static str,
39    output_method: &'static str,
40    display_only: &'static str,
41    save_to_file: &'static str,
42    select: &'static str,
43    file_path: &'static str,
44    file_saved: &'static str,
45    security_warning: &'static str,
46    plaintext_warning: &'static str,
47    save_securely: &'static str,
48    dont_share: &'static str,
49    recommend_encrypted: &'static str,
50
51    // Encrypted key creation
52    create_encrypted_title: &'static str,
53    choose_method: &'static str,
54    generate_new: &'static str,
55    import_existing: &'static str,
56    generating: &'static str,
57    enter_private_key: &'static str,
58    private_key_empty: &'static str,
59    keypair_ready: &'static str,
60    keystore_recommended: &'static str,
61    show_encrypted_string: &'static str,
62    keystore_created: &'static str,
63    private_key_encrypted: &'static str,
64    important_note: &'static str,
65    keep_safe: &'static str,
66    lost_password_warning: &'static str,
67    backup_recommended: &'static str,
68    encrypted_private_key: &'static str,
69    keep_safe_both: &'static str,
70
71    // Key decryption
72    decrypt_title: &'static str,
73    input_method: &'static str,
74    from_keystore: &'static str,
75    from_encrypted_string: &'static str,
76    encrypted_key: &'static str,
77    enter_password: &'static str,
78    decrypt_success: &'static str,
79    file_not_exist: &'static str,
80    dont_share_warning: &'static str,
81    delete_plaintext: &'static str,
82    use_encryption: &'static str,
83
84    // Password
85    set_password: &'static str,
86    new_password: &'static str,
87    confirm_password: &'static str,
88    password_empty: &'static str,
89    password_min_length: &'static str,
90    password_mismatch: &'static str,
91    password_set: &'static str,
92
93    // Errors
94    invalid_choice: &'static str,
95    write_failed: &'static str,
96}
97
98impl Texts {
99    fn chinese() -> Self {
100        Self {
101            title: "  Sol-SafeKey - Solana 密钥管理工具",
102            core_functions: "核心功能 (只需3个操作):",
103            create_plain: "  {}  创建明文私钥",
104            create_encrypted: "  {}  创建加密私钥(bot)",
105            decrypt: "  {}  解密私钥",
106            exit: "  {}  退出",
107            select_option: "请输入选项 [0-14]: ",
108            goodbye: "👋 再见!",
109            invalid_option: "❌ 无效选项,请重新选择",
110            continue_use: "是否继续使用? [Y/n]: ",
111
112            create_plain_title: "  创建明文私钥",
113            keypair_generated: "✅ 密钥对生成成功!",
114            public_key: "公钥地址:",
115            private_key: "私钥:",
116            output_method: "输出方式:",
117            display_only: "  1. 仅显示 (当前已显示)",
118            save_to_file: "  2. 保存到文件",
119            select: "请选择 [1/2]: ",
120            file_path: "文件路径 (默认: keypair.json): ",
121            file_saved: "✅ 已保存到文件",
122            security_warning: "⚠️  安全警告:",
123            plaintext_warning: "  • 明文私钥非常不安全",
124            save_securely: "  • 请立即保存到安全位置",
125            dont_share: "  • 不要分享给任何人",
126            recommend_encrypted: "  • 建议使用 '创建加密私钥' 功能",
127
128            create_encrypted_title: "  创建加密私钥",
129            choose_method: "选择方式:",
130            generate_new: "  1. 生成新的密钥对并加密",
131            import_existing: "  2. 导入现有私钥并加密",
132            generating: "🎲 生成新的密钥对...",
133            enter_private_key: "请输入私钥 (base58 格式): ",
134            private_key_empty: "私钥不能为空",
135            keypair_ready: "✅ 密钥对准备完成",
136            keystore_recommended: "  1. 保存为 Keystore 文件 (推荐)",
137            show_encrypted_string: "  2. 显示加密字符串",
138            keystore_created: "  ✅ Keystore 创建成功!",
139            private_key_encrypted: "🔒 私钥已加密保存",
140            important_note: "⚠️  重要提示:",
141            keep_safe: "  • 请妥善保管 Keystore 文件和密码",
142            lost_password_warning: "  • 丢失密码将无法恢复钱包",
143            backup_recommended: "  • 建议备份到安全位置",
144            encrypted_private_key: "加密后的私钥:",
145            keep_safe_both: "⚠️  提示: 请妥善保管加密私钥和密码",
146
147            decrypt_title: "  解密私钥",
148            input_method: "输入方式:",
149            from_keystore: "  1. 从 Keystore 文件读取",
150            from_encrypted_string: "  2. 输入加密字符串",
151            encrypted_key: "加密的私钥: ",
152            enter_password: "请输入密码: ",
153            decrypt_success: "  ✅ 解密成功!",
154            file_not_exist: "文件不存在: {}",
155            dont_share_warning: "  • 请勿分享私钥给任何人",
156            delete_plaintext: "  • 使用完毕后请立即删除明文私钥文件",
157            use_encryption: "  • 建议使用加密方式保存",
158
159            set_password: "设置加密密码 (至少 10 个字符):",
160            new_password: "新密码: ",
161            confirm_password: "确认密码: ",
162            password_empty: "密码不能为空",
163            password_min_length: "密码长度至少 10 个字符",
164            password_mismatch: "两次密码不一致",
165            password_set: "✅ 密码设置成功",
166
167            invalid_choice: "无效选项",
168            write_failed: "写入文件失败: {}",
169        }
170    }
171
172    fn english() -> Self {
173        Self {
174            title: "  Sol-SafeKey - Solana Key Management Tool",
175            core_functions: "Core Functions (3 operations):",
176            create_plain: "  {}  Create Plain Private Key",
177            create_encrypted: "  {}  Create Encrypted Private Key (Bot)",
178            decrypt: "  {}  Decrypt Private Key",
179            exit: "  {}  Exit",
180            select_option: "Select option [0-14]: ",
181            goodbye: "👋 Goodbye!",
182            invalid_option: "❌ Invalid option, please try again",
183            continue_use: "Continue? [Y/n]: ",
184
185            create_plain_title: "  Create Plain Private Key",
186            keypair_generated: "✅ Keypair generated successfully!",
187            public_key: "Public Key:",
188            private_key: "Private Key:",
189            output_method: "Output Method:",
190            display_only: "  1. Display Only (already shown)",
191            save_to_file: "  2. Save to File",
192            select: "Select [1/2]: ",
193            file_path: "File path (default: keypair.json): ",
194            file_saved: "✅ Saved to file",
195            security_warning: "⚠️  Security Warning:",
196            plaintext_warning: "  • Plaintext private key is very insecure",
197            save_securely: "  • Save to a secure location immediately",
198            dont_share: "  • Never share with anyone",
199            recommend_encrypted: "  • Consider using 'Create Encrypted Private Key'",
200
201            create_encrypted_title: "  Create Encrypted Private Key",
202            choose_method: "Choose Method:",
203            generate_new: "  1. Generate new keypair and encrypt",
204            import_existing: "  2. Import existing private key and encrypt",
205            generating: "🎲 Generating new keypair...",
206            enter_private_key: "Enter private key (base58 format): ",
207            private_key_empty: "Private key cannot be empty",
208            keypair_ready: "✅ Keypair ready",
209            keystore_recommended: "  1. Save as Keystore file (Recommended)",
210            show_encrypted_string: "  2. Show encrypted string",
211            keystore_created: "  ✅ Keystore created successfully!",
212            private_key_encrypted: "🔒 Private key encrypted and saved",
213            important_note: "⚠️  Important:",
214            keep_safe: "  • Keep Keystore file and password safe",
215            lost_password_warning: "  • Lost password = lost wallet",
216            backup_recommended: "  • Backup to a secure location",
217            encrypted_private_key: "Encrypted Private Key:",
218            keep_safe_both: "⚠️  Note: Keep encrypted key and password safe",
219
220            decrypt_title: "  Decrypt Private Key",
221            input_method: "Input Method:",
222            from_keystore: "  1. From Keystore file",
223            from_encrypted_string: "  2. Enter encrypted string",
224            encrypted_key: "Encrypted key: ",
225            enter_password: "Enter password: ",
226            decrypt_success: "  ✅ Decryption successful!",
227            file_not_exist: "File not found: {}",
228            dont_share_warning: "  • Never share private key with anyone",
229            delete_plaintext: "  • Delete plaintext key file after use",
230            use_encryption: "  • Consider using encryption for storage",
231
232            set_password: "Set encryption password (minimum 10 characters):",
233            new_password: "New password: ",
234            confirm_password: "Confirm password: ",
235            password_empty: "Password cannot be empty",
236            password_min_length: "Password must be at least 10 characters",
237            password_mismatch: "Passwords do not match",
238            password_set: "✅ Password set successfully",
239
240            invalid_choice: "Invalid choice",
241            write_failed: "Write failed: {}",
242        }
243    }
244}
245
246/// 选择语言
247fn select_language() -> Result<Language, String> {
248    println!("\n{}", "=".repeat(50).cyan());
249    println!("{}", "  Language / 语言选择".cyan().bold());
250    println!("{}", "=".repeat(50).cyan());
251    println!();
252    println!("  {}  English", "1.".green().bold());
253    println!("  {}  中文", "2.".green().bold());
254    println!();
255    print!("Select / 选择 [1/2]: ");
256    io::stdout().flush().map_err(|e| e.to_string())?;
257
258    let mut choice = String::new();
259    io::stdin().read_line(&mut choice).map_err(|e| e.to_string())?;
260    let choice = choice.trim();
261
262    match choice {
263        "1" => Ok(Language::English),
264        "2" => Ok(Language::Chinese),
265        _ => {
266            println!("\n{}", "❌ Invalid option / 无效选项".red());
267            select_language()
268        }
269    }
270}
271
272/// Session state to hold unlocked keypair
273struct SessionState {
274    keypair: Option<Keypair>,
275    keystore_path: Option<String>,
276}
277
278impl SessionState {
279    fn new() -> Self {
280        Self {
281            keypair: None,
282            keystore_path: None,
283        }
284    }
285
286    fn is_unlocked(&self) -> bool {
287        self.keypair.is_some()
288    }
289
290    fn unlock(&mut self, keypair: Keypair, path: String) {
291        self.keypair = Some(keypair);
292        self.keystore_path = Some(path);
293    }
294
295    fn get_keypair(&self) -> Option<&Keypair> {
296        self.keypair.as_ref()
297    }
298
299    fn lock(&mut self) {
300        self.keypair = None;
301        self.keystore_path = None;
302    }
303}
304
305/// 显示主菜单并处理用户选择
306pub fn show_main_menu() -> Result<(), String> {
307    // 首先选择语言
308    let lang = select_language()?;
309    let texts = match lang {
310        Language::Chinese => Texts::chinese(),
311        Language::English => Texts::english(),
312    };
313
314    // Create session state to hold unlocked keypair
315    let mut session = SessionState::new();
316
317    loop {
318        println!("\n{}", "=".repeat(50).cyan());
319        println!("{}", texts.title.cyan().bold());
320        println!("{}", "=".repeat(50).cyan());
321        println!();
322        println!("{}", texts.core_functions);
323        println!();
324        println!("  {}  {}", "1.".green().bold(), &texts.create_plain[6..]);
325        println!("  {}  {}", "2.".green().bold(), &texts.create_encrypted[6..]);
326        println!("  {}  {}", "3.".green().bold(), &texts.decrypt[6..]);
327
328        // Show unlock/lock status
329        println!();
330        if session.is_unlocked() {
331            if lang == Language::Chinese {
332                println!("  🔓 {} {}", "钱包已解锁:".green().bold(), session.get_keypair().unwrap().pubkey().to_string().bright_white());
333                println!("  {}  {}", "L.".yellow().bold(), "锁定钱包".yellow());
334            } else {
335                println!("  🔓 {} {}", "Wallet Unlocked:".green().bold(), session.get_keypair().unwrap().pubkey().to_string().bright_white());
336                println!("  {}  {}", "L.".yellow().bold(), "Lock Wallet".yellow());
337            }
338        } else {
339            if lang == Language::Chinese {
340                println!("  🔒 {} {}", "钱包状态:".red(), "未解锁".red());
341                println!("  {}  {}", "U.".green().bold(), "解锁钱包(用于Solana操作)".green());
342            } else {
343                println!("  🔒 {} {}", "Wallet Status:".red(), "Locked".red());
344                println!("  {}  {}", "U.".green().bold(), "Unlock Wallet (for Solana Operations)".green());
345            }
346        }
347
348        // Advanced security features
349        #[cfg(feature = "2fa")]
350        {
351            println!();
352            if lang == Language::Chinese {
353                println!("{}", "  高级安全功能:".bright_magenta().bold());
354            } else {
355                println!("{}", "  Advanced Security:".bright_magenta().bold());
356            }
357            println!("  {}  {}", "4.".bright_magenta().bold(), if lang == Language::Chinese { "设置 2FA 认证" } else { "Setup 2FA Authentication" });
358            println!("  {}  {}", "5.".bright_magenta().bold(), if lang == Language::Chinese { "生成三因子钱包" } else { "Generate Triple-Factor Wallet" });
359            println!("  {}  {}", "6.".bright_magenta().bold(), if lang == Language::Chinese { "解锁三因子钱包" } else { "Unlock Triple-Factor Wallet" });
360        }
361
362        // Solana operations (if feature is enabled)
363        #[cfg(feature = "solana-ops")]
364        {
365            println!();
366            if lang == Language::Chinese {
367                println!("{}", "  Solana 链上操作:".bright_blue().bold());
368            } else {
369                println!("{}", "  Solana Operations:".bright_blue().bold());
370            }
371            #[cfg(feature = "2fa")]
372            {
373                println!("  {}  {}", "7.".bright_cyan().bold(), if lang == Language::Chinese { "查询 SOL 余额" } else { "Check SOL Balance" });
374                println!("  {}  {}", "8.".bright_cyan().bold(), if lang == Language::Chinese { "转账 SOL" } else { "Transfer SOL" });
375                println!("  {}  {}", "9.".bright_cyan().bold(), if lang == Language::Chinese { "创建 WSOL ATA" } else { "Create WSOL ATA" });
376                println!("  {}  {}", "10.".bright_cyan().bold(), if lang == Language::Chinese { "包装 SOL → WSOL" } else { "Wrap SOL → WSOL" });
377                println!("  {}  {}", "11.".bright_cyan().bold(), if lang == Language::Chinese { "解包 WSOL → SOL" } else { "Unwrap WSOL → SOL" });
378                println!("  {}  {}", "12.".bright_cyan().bold(), if lang == Language::Chinese { "关闭 WSOL ATA" } else { "Close WSOL ATA" });
379                println!("  {}  {}", "13.".bright_cyan().bold(), if lang == Language::Chinese { "转账 SPL 代币" } else { "Transfer SPL Token" });
380                println!("  {}  {}", "14.".bright_cyan().bold(), if lang == Language::Chinese { "创建 Nonce 账户" } else { "Create Nonce Account" });
381
382                #[cfg(feature = "sol-trade-sdk")]
383                println!("  {}  {}", "15.".bright_magenta().bold(), if lang == Language::Chinese { "Pump.fun 卖出代币" } else { "Pump.fun Sell Tokens" });
384                #[cfg(feature = "sol-trade-sdk")]
385                println!("  {}  {}", "16.".bright_magenta().bold(), if lang == Language::Chinese { "PumpSwap 卖出代币" } else { "PumpSwap Sell Tokens" });
386                #[cfg(feature = "sol-trade-sdk")]
387                println!("  {}  {}", "17.".bright_magenta().bold(), if lang == Language::Chinese { "Pump.fun 返现(查看与领取)" } else { "Pump.fun Cashback (View & Claim)" });
388                #[cfg(feature = "sol-trade-sdk")]
389                println!("  {}  {}", "18.".bright_magenta().bold(), if lang == Language::Chinese { "PumpSwap 返现(查看与领取)" } else { "PumpSwap Cashback (View & Claim)" });
390            }
391            #[cfg(not(feature = "2fa"))]
392            {
393                println!("  {}  {}", "4.".bright_cyan().bold(), if lang == Language::Chinese { "查询 SOL 余额" } else { "Check SOL Balance" });
394                println!("  {}  {}", "5.".bright_cyan().bold(), if lang == Language::Chinese { "转账 SOL" } else { "Transfer SOL" });
395                println!("  {}  {}", "6.".bright_cyan().bold(), if lang == Language::Chinese { "创建 WSOL ATA" } else { "Create WSOL ATA" });
396                println!("  {}  {}", "7.".bright_cyan().bold(), if lang == Language::Chinese { "包装 SOL → WSOL" } else { "Wrap SOL → WSOL" });
397                println!("  {}  {}", "8.".bright_cyan().bold(), if lang == Language::Chinese { "解包 WSOL → SOL" } else { "Unwrap WSOL → SOL" });
398                println!("  {}  {}", "9.".bright_cyan().bold(), if lang == Language::Chinese { "关闭 WSOL ATA" } else { "Close WSOL ATA" });
399                println!("  {}  {}", "10.".bright_cyan().bold(), if lang == Language::Chinese { "转账 SPL 代币" } else { "Transfer SPL Token" });
400                println!("  {}  {}", "11.".bright_cyan().bold(), if lang == Language::Chinese { "创建 Nonce 账户" } else { "Create Nonce Account" });
401
402                #[cfg(feature = "sol-trade-sdk")]
403                println!("  {}  {}", "12.".bright_magenta().bold(), if lang == Language::Chinese { "Pump.fun 卖出代币" } else { "Pump.fun Sell Tokens" });
404                #[cfg(feature = "sol-trade-sdk")]
405                println!("  {}  {}", "13.".bright_magenta().bold(), if lang == Language::Chinese { "PumpSwap 卖出代币" } else { "PumpSwap Sell Tokens" });
406                #[cfg(feature = "sol-trade-sdk")]
407                println!("  {}  {}", "14.".bright_magenta().bold(), if lang == Language::Chinese { "Pump.fun 返现(查看与领取)" } else { "Pump.fun Cashback (View & Claim)" });
408                #[cfg(feature = "sol-trade-sdk")]
409                println!("  {}  {}", "15.".bright_magenta().bold(), if lang == Language::Chinese { "PumpSwap 返现(查看与领取)" } else { "PumpSwap Cashback (View & Claim)" });
410            }
411        }
412
413        println!();
414        println!("  {}  {}", "0.".red().bold(), &texts.exit[6..]);
415        println!();
416        print!("{}", texts.select_option);
417        io::stdout().flush().map_err(|e| e.to_string())?;
418
419        let mut choice = String::new();
420        io::stdin().read_line(&mut choice).map_err(|e| e.to_string())?;
421        let choice = choice.trim();
422
423        match choice.to_lowercase().as_str() {
424            "1" => create_plain_key_interactive(&texts)?,
425            "2" => create_encrypted_key_interactive(&texts)?,
426            "3" => decrypt_key_interactive(&texts)?,
427
428            // Unlock/Lock wallet
429            "u" => {
430                if session.is_unlocked() {
431                    if lang == Language::Chinese {
432                        println!("\n✅ 钱包已经解锁!");
433                    } else {
434                        println!("\n✅ Wallet already unlocked!");
435                    }
436                } else {
437                    if let Err(e) = unlock_wallet_interactive(&mut session, lang) {
438                        eprintln!("❌ {}", e);
439                    }
440                }
441                // 解锁/锁定后直接回到菜单,不再问「是否继续使用」
442                continue;
443            }
444            "l" => {
445                if session.is_unlocked() {
446                    session.lock();
447                    if lang == Language::Chinese {
448                        println!("\n🔒 钱包已锁定");
449                    } else {
450                        println!("\n🔒 Wallet locked");
451                    }
452                } else {
453                    if lang == Language::Chinese {
454                        println!("\n⚠️ 钱包未解锁");
455                    } else {
456                        println!("\n⚠️ Wallet not unlocked");
457                    }
458                }
459                continue;
460            }
461
462            // Advanced security features (2FA)
463            #[cfg(feature = "2fa")]
464            "4" => {
465                if let Err(e) = setup_2fa_interactive(lang) {
466                    eprintln!("❌ {}", e);
467                }
468            }
469            #[cfg(feature = "2fa")]
470            "5" => {
471                if let Err(e) = generate_triple_factor_wallet_interactive(lang) {
472                    eprintln!("❌ {}", e);
473                }
474            }
475            #[cfg(feature = "2fa")]
476            "6" => {
477                if let Err(e) = unlock_triple_factor_wallet_interactive(lang) {
478                    eprintln!("❌ {}", e);
479                }
480            }
481
482            // Solana operations
483            #[cfg(all(feature = "solana-ops", feature = "2fa"))]
484            "7" | "8" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" => {
485                if let Err(e) = handle_solana_operation(choice, lang, &mut session) {
486                    eprintln!("❌ {}", e);
487                }
488            }
489            #[cfg(all(feature = "solana-ops", not(feature = "2fa")))]
490            "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12" | "13" | "14" | "15" => {
491                if let Err(e) = handle_solana_operation(choice, lang, &mut session) {
492                    eprintln!("❌ {}", e);
493                }
494            }
495
496            "0" => {
497                println!("\n{}", texts.goodbye.cyan());
498                break;
499            }
500            _ => {
501                println!("\n{}", texts.invalid_option.red());
502                continue;
503            }
504        }
505
506        // 询问是否继续
507        println!();
508        print!("{}", texts.continue_use);
509        io::stdout().flush().map_err(|e| e.to_string())?;
510
511        let mut continue_choice = String::new();
512        io::stdin().read_line(&mut continue_choice).map_err(|e| e.to_string())?;
513        let continue_choice = continue_choice.trim().to_lowercase();
514
515        if continue_choice == "n" || continue_choice == "no" {
516            println!("\n{}", texts.goodbye.cyan());
517            break;
518        }
519    }
520
521    Ok(())
522}
523
524/// 功能1: 创建明文私钥
525fn create_plain_key_interactive(texts: &Texts) -> Result<(), String> {
526    println!("\n{}", "=".repeat(50).yellow());
527    println!("{}", texts.create_plain_title.yellow().bold());
528    println!("{}", "=".repeat(50).yellow());
529    println!();
530
531    // 生成密钥对
532    let keypair = KeyManager::generate_keypair();
533    let pubkey = keypair.pubkey();
534    let private_key = keypair.to_base58_string();
535
536    println!("{}", texts.keypair_generated.green().bold());
537    println!();
538    println!("{} {}", texts.public_key.cyan(), pubkey.to_string().white().bold());
539    println!("{} {}", texts.private_key.red().bold(), private_key);
540    println!();
541
542    // 询问输出方式
543    println!("{}",texts.output_method);
544    println!("{}", texts.display_only);
545    println!("{}", texts.save_to_file);
546    println!();
547    print!("{}", texts.select);
548    io::stdout().flush().map_err(|e| e.to_string())?;
549
550    let mut output_choice = String::new();
551    io::stdin().read_line(&mut output_choice).map_err(|e| e.to_string())?;
552    let output_choice = output_choice.trim();
553
554    if output_choice == "2" {
555        print!("{}", texts.file_path);
556        io::stdout().flush().map_err(|e| e.to_string())?;
557
558        let mut file_path = String::new();
559        io::stdin().read_line(&mut file_path).map_err(|e| e.to_string())?;
560        let file_path = file_path.trim();
561        let file_path = if file_path.is_empty() {
562            "keypair.json"
563        } else {
564            file_path
565        };
566
567        // 保存为 Solana keypair JSON 格式 (数组格式)
568        let bytes = keypair.to_bytes();
569        let json = serde_json::to_string(&bytes.to_vec())
570            .map_err(|e| format!("{}", texts.write_failed.replace("{}", &e.to_string())))?;
571
572        std::fs::write(file_path, json)
573            .map_err(|e| format!("{}", texts.write_failed.replace("{}", &e.to_string())))?;
574
575        println!();
576        println!("{}", texts.file_saved.green());
577        println!("{} {}", texts.file_path.trim_end_matches(':'), file_path);
578    }
579
580    println!();
581    println!("{}", texts.security_warning.yellow().bold());
582    println!("{}", texts.plaintext_warning);
583    println!("{}", texts.save_securely);
584    println!("{}", texts.dont_share);
585    println!("{}", texts.recommend_encrypted);
586
587    Ok(())
588}
589
590/// 功能2: 创建加密私钥
591fn create_encrypted_key_interactive(texts: &Texts) -> Result<(), String> {
592    println!("\n{}", "=".repeat(50).yellow());
593    println!("{}", texts.create_encrypted_title.yellow().bold());
594    println!("{}", "=".repeat(50).yellow());
595    println!();
596
597    // 询问是生成新的还是导入现有私钥
598    println!("{}", texts.choose_method);
599    println!("{}", texts.generate_new);
600    println!("{}", texts.import_existing);
601    println!();
602    print!("{}", texts.select);
603    io::stdout().flush().map_err(|e| e.to_string())?;
604
605    let mut source_choice = String::new();
606    io::stdin().read_line(&mut source_choice).map_err(|e| e.to_string())?;
607    let source_choice = source_choice.trim();
608
609    let keypair = match source_choice {
610        "1" => {
611            // 生成新密钥对
612            println!();
613            println!("{}", texts.generating.cyan());
614            KeyManager::generate_keypair()
615        }
616        "2" => {
617            // 导入现有私钥
618            println!();
619            print!("{}", texts.enter_private_key);
620            io::stdout().flush().map_err(|e| e.to_string())?;
621
622            let mut private_key = String::new();
623            io::stdin().read_line(&mut private_key).map_err(|e| e.to_string())?;
624            let private_key = private_key.trim();
625
626            if private_key.is_empty() {
627                return Err(texts.private_key_empty.to_string());
628            }
629
630            Keypair::from_base58_string(private_key)
631        }
632        _ => {
633            return Err(texts.invalid_choice.to_string());
634        }
635    };
636
637    let pubkey = keypair.pubkey();
638
639    println!();
640    println!("{}", texts.keypair_ready.green());
641    println!("{} {}", texts.public_key.cyan(), pubkey);
642    println!();
643
644    // 获取密码
645    let password = read_password_confirmed(texts)?;
646
647    // 询问输出方式
648    println!();
649    println!("{}", texts.output_method);
650    println!("{}", texts.keystore_recommended);
651    println!("{}", texts.show_encrypted_string);
652    println!();
653    print!("{}", texts.select);
654    io::stdout().flush().map_err(|e| e.to_string())?;
655
656    let mut output_choice = String::new();
657    io::stdin().read_line(&mut output_choice).map_err(|e| e.to_string())?;
658    let output_choice = output_choice.trim();
659
660    match output_choice {
661        "1" => {
662            // 保存为文件
663            print!("{}", texts.file_path.replace("keypair", "wallet"));
664            io::stdout().flush().map_err(|e| e.to_string())?;
665
666            let mut file_path = String::new();
667            io::stdin().read_line(&mut file_path).map_err(|e| e.to_string())?;
668            let file_path = file_path.trim();
669            let file_path = if file_path.is_empty() {
670                "wallet.json"
671            } else {
672                file_path
673            };
674
675            let keystore_json = KeyManager::keypair_to_encrypted_json(&keypair, &password)?;
676            std::fs::write(file_path, keystore_json)
677                .map_err(|e| format!("{}", texts.write_failed.replace("{}", &e.to_string())))?;
678
679            println!();
680            println!("{}", "=".repeat(50).green());
681            println!("{}", texts.keystore_created.green().bold());
682            println!("{}", "=".repeat(50).green());
683            println!();
684            println!("{} {}", texts.file_path.trim_end_matches(':'), file_path);
685            println!("{} {}", texts.public_key.cyan(), pubkey);
686            println!("{}", texts.private_key_encrypted.green());
687            println!();
688            println!("{}", texts.important_note.yellow().bold());
689            println!("{}", texts.keep_safe);
690            println!("{}", texts.lost_password_warning);
691            println!("{}", texts.backup_recommended);
692        }
693        "2" => {
694            // 显示加密字符串
695            let private_key = keypair.to_base58_string();
696            let encrypted = KeyManager::encrypt_with_password(&private_key, &password)?;
697
698            println!();
699            println!("{}", texts.keypair_ready.green().bold());
700            println!();
701            println!("{} {}", texts.public_key.cyan(), pubkey);
702            println!("{}", texts.encrypted_private_key.cyan());
703            println!("{}", encrypted);
704            println!();
705            println!("{}", texts.keep_safe_both.yellow());
706        }
707        _ => {
708            return Err(texts.invalid_choice.to_string());
709        }
710    }
711
712    Ok(())
713}
714
715/// 功能3: 解密私钥
716fn decrypt_key_interactive(texts: &Texts) -> Result<(), String> {
717    println!("\n{}", "=".repeat(50).yellow());
718    println!("{}", texts.decrypt_title.yellow().bold());
719    println!("{}", "=".repeat(50).yellow());
720    println!();
721
722    // 选择输入方式
723    println!("{}", texts.input_method);
724    println!("{}", texts.from_keystore);
725    println!("{}", texts.from_encrypted_string);
726    println!();
727    print!("{}", texts.select);
728    io::stdout().flush().map_err(|e| e.to_string())?;
729
730    let mut input_choice = String::new();
731    io::stdin().read_line(&mut input_choice).map_err(|e| e.to_string())?;
732    let input_choice = input_choice.trim();
733
734    let (private_key, pubkey) = match input_choice {
735        "1" => {
736            // 从文件读取
737            print!("{}", texts.file_path.trim_end_matches("(默认: keypair.json): ").trim_end_matches("(default: keypair.json): "));
738            io::stdout().flush().map_err(|e| e.to_string())?;
739
740            let mut file_path = String::new();
741            io::stdin().read_line(&mut file_path).map_err(|e| e.to_string())?;
742            let file_path = file_path.trim();
743
744            if !std::path::Path::new(file_path).exists() {
745                return Err(format!("{}", texts.file_not_exist.replace("{}", file_path)));
746            }
747
748            println!();
749            let password = prompt_password(texts.enter_password, texts)?;
750
751            let keystore_json = std::fs::read_to_string(file_path)
752                .map_err(|e| format!("{}", texts.write_failed.replace("{}", &e.to_string())))?;
753
754            let keypair = KeyManager::keypair_from_encrypted_json(&keystore_json, &password)?;
755            let pubkey = keypair.pubkey();
756            let private_key = keypair.to_base58_string();
757
758            (private_key, pubkey)
759        }
760        "2" => {
761            // 输入加密字符串
762            print!("{}", texts.encrypted_key);
763            io::stdout().flush().map_err(|e| e.to_string())?;
764
765            let mut encrypted = String::new();
766            io::stdin().read_line(&mut encrypted).map_err(|e| e.to_string())?;
767            let encrypted = encrypted.trim();
768
769            println!();
770            let password = prompt_password(texts.enter_password, texts)?;
771
772            let private_key = KeyManager::decrypt_with_password(encrypted, &password)?;
773            let keypair = Keypair::from_base58_string(&private_key);
774            let pubkey = keypair.pubkey();
775
776            (private_key, pubkey)
777        }
778        _ => {
779            return Err(texts.invalid_choice.to_string());
780        }
781    };
782
783    println!();
784    println!("{}", "=".repeat(50).green());
785    println!("{}", texts.decrypt_success.green().bold());
786    println!("{}", "=".repeat(50).green());
787    println!();
788    println!("{} {}", texts.public_key.cyan(), pubkey);
789    println!("{} {}", texts.private_key.red().bold(), private_key);
790    println!();
791
792    // 询问输出方式
793    println!("{}", texts.output_method);
794    println!("{}", texts.display_only);
795    println!("{}", texts.save_to_file);
796    println!();
797    print!("{}", texts.select);
798    io::stdout().flush().map_err(|e| e.to_string())?;
799
800    let mut output_choice = String::new();
801    io::stdin().read_line(&mut output_choice).map_err(|e| e.to_string())?;
802    let output_choice = output_choice.trim();
803
804    if output_choice == "2" {
805        let default_filename = if texts.file_path.contains("默认") {
806            "decrypted_key.txt"
807        } else {
808            "decrypted_key.txt"
809        };
810
811        print!("{}", texts.file_path.replace("keypair.json", default_filename));
812        io::stdout().flush().map_err(|e| e.to_string())?;
813
814        let mut file_path = String::new();
815        io::stdin().read_line(&mut file_path).map_err(|e| e.to_string())?;
816        let file_path = file_path.trim();
817        let file_path = if file_path.is_empty() {
818            default_filename
819        } else {
820            file_path
821        };
822
823        let content = format!("{} {}\n{} {}\n", texts.public_key, pubkey, texts.private_key.trim_end_matches(':'), private_key);
824        std::fs::write(file_path, content)
825            .map_err(|e| format!("{}", texts.write_failed.replace("{}", &e.to_string())))?;
826
827        println!();
828        println!("{}", texts.file_saved.green());
829        println!("{} {}", texts.file_path.trim_end_matches(':'), file_path);
830    }
831
832    println!();
833    println!("{}", texts.security_warning.yellow().bold());
834    println!("{}", texts.dont_share_warning);
835    println!("{}", texts.delete_plaintext);
836    println!("{}", texts.use_encryption);
837
838    Ok(())
839}
840
841/// 读取密码(临时显示明文用于调试)
842/// Prompt and read password securely
843fn prompt_password(prompt: &str, texts: &Texts) -> Result<String, String> {
844    print!("{}", prompt);
845    io::stdout().flush().map_err(|e| e.to_string())?;
846
847    // 临时使用明文输入进行调试
848    let mut password = String::new();
849    io::stdin().read_line(&mut password)
850        .map_err(|e| format!("{}", texts.write_failed.replace("{}", &e.to_string())))?;
851
852    let password = password.trim().to_string();
853    println!("DEBUG: 读取到的密码: '{}' (长度: {})", password, password.len());
854
855    Ok(password)
856
857    // 原来的隐藏输入代码(调试完成后恢复)
858    // let password = rpassword::read_password()
859    //     .map_err(|e| format!("{}", texts.write_failed.replace("{}", &e.to_string())))?;
860    // Ok(password.trim().to_string())
861}
862
863/// Unlock wallet interactively and store in session
864fn unlock_wallet_interactive(session: &mut SessionState, language: Language) -> Result<(), String> {
865    use rpassword;
866
867    println!();
868    if language == Language::Chinese {
869        println!("{}", "  解锁钱包".cyan().bold());
870        print!("Keystore 文件路径 [keystore.json]: ");
871    } else {
872        println!("{}", "  Unlock Wallet".cyan().bold());
873        print!("Keystore file path [keystore.json]: ");
874    }
875    io::stdout().flush().map_err(|e| e.to_string())?;
876
877    let mut keystore_path = String::new();
878    io::stdin().read_line(&mut keystore_path).map_err(|e| e.to_string())?;
879    let keystore_path = keystore_path.trim();
880    let keystore_path = if keystore_path.is_empty() {
881        "keystore.json"
882    } else {
883        keystore_path
884    };
885
886    // Read encrypted file
887    let file_content = std::fs::read_to_string(keystore_path)
888        .map_err(|e| format!("Failed to read keystore: {}", e))?;
889
890    // Parse JSON to get encryption type
891    let json: serde_json::Value = serde_json::from_str(&file_content)
892        .map_err(|e| format!("Failed to parse keystore: {}", e))?;
893
894    let encryption_type = json["encryption_type"].as_str().unwrap_or("password_only");
895
896    // Decrypt keypair
897    let keypair = match encryption_type {
898        "password_only" => {
899            // Simple password-based decryption
900            let password = rpassword::prompt_password(
901                if language == Language::Chinese { "输入密码: " } else { "Enter password: " }
902            ).map_err(|e| format!("Failed to read password: {}", e))?;
903
904            KeyManager::keypair_from_encrypted_json(&file_content, &password)
905                .map_err(|e| format!("Failed to decrypt keystore: {}", e))?
906        }
907        "triple_factor_v1" => {
908            return Err("Triple-factor wallets not yet supported in interactive mode. Please use the CLI.".to_string());
909        }
910        _ => {
911            return Err(format!("Unknown encryption type: {}", encryption_type));
912        }
913    };
914
915    // Store in session
916    session.unlock(keypair, keystore_path.to_string());
917
918    if language == Language::Chinese {
919        println!("✅ 钱包解锁成功!");
920        println!("📍 钱包地址: {}", session.get_keypair().unwrap().pubkey());
921        println!("💡 提示: 在本次会话中,Solana操作将使用此钱包,无需重复输入密码");
922    } else {
923        println!("✅ Wallet unlocked successfully!");
924        println!("📍 Wallet address: {}", session.get_keypair().unwrap().pubkey());
925        println!("💡 Tip: Solana operations in this session will use this wallet without re-entering password");
926    }
927
928    Ok(())
929}
930
931/// Handle Solana operation using session keypair
932#[cfg(feature = "solana-ops")]
933fn handle_solana_operation(choice: &str, language: Language, session: &mut SessionState) -> Result<(), String> {
934    // Convert Language to operations::Language
935    let ops_language = match language {
936        Language::English => crate::operations::Language::English,
937        Language::Chinese => crate::operations::Language::Chinese,
938    };
939
940    // Check if wallet is unlocked
941    let keypair = if let Some(kp) = session.get_keypair() {
942        kp
943    } else {
944        // Wallet not unlocked, prompt user to unlock first
945        if language == Language::Chinese {
946            println!("\n⚠️  请先使用 'U' 选项解锁钱包");
947        } else {
948            println!("\n⚠️  Please unlock wallet first using 'U' option");
949        }
950        return Ok(());
951    };
952
953    if language == Language::Chinese {
954        println!("\n📍 使用钱包: {}", keypair.pubkey());
955    } else {
956        println!("\n📍 Using wallet: {}", keypair.pubkey());
957    }
958
959    // Call the appropriate operation
960    #[cfg(feature = "2fa")]
961    let result = match choice {
962        "7" => crate::operations::check_balance(&keypair, ops_language),
963        "8" => crate::operations::transfer_sol(&keypair, ops_language),
964        "9" => crate::operations::create_wsol_ata(&keypair, ops_language),
965        "10" => crate::operations::wrap_sol(&keypair, ops_language),
966        "11" => crate::operations::unwrap_sol(&keypair, ops_language),
967        "12" => crate::operations::close_wsol_ata(&keypair, ops_language),
968        "13" => crate::operations::transfer_token(&keypair, ops_language),
969        "14" => crate::operations::create_nonce_account(&keypair, ops_language),
970        #[cfg(feature = "sol-trade-sdk")]
971        "15" => crate::operations::pumpfun_sell_interactive(&keypair, ops_language),
972        #[cfg(feature = "sol-trade-sdk")]
973        "16" => crate::operations::pumpswap_sell_interactive(&keypair, ops_language),
974        #[cfg(feature = "sol-trade-sdk")]
975        "17" => crate::operations::pumpfun_cashback_interactive(&keypair, ops_language),
976        #[cfg(feature = "sol-trade-sdk")]
977        "18" => crate::operations::pumpswap_cashback_interactive(&keypair, ops_language),
978        _ => Err("Invalid operation".to_string()),
979    };
980
981    #[cfg(not(feature = "2fa"))]
982    let result = match choice {
983        "4" => crate::operations::check_balance(&keypair, ops_language),
984        "5" => crate::operations::transfer_sol(&keypair, ops_language),
985        "6" => crate::operations::create_wsol_ata(&keypair, ops_language),
986        "7" => crate::operations::wrap_sol(&keypair, ops_language),
987        "8" => crate::operations::unwrap_sol(&keypair, ops_language),
988        "9" => crate::operations::close_wsol_ata(&keypair, ops_language),
989        "10" => crate::operations::transfer_token(&keypair, ops_language),
990        "11" => crate::operations::create_nonce_account(&keypair, ops_language),
991        #[cfg(feature = "sol-trade-sdk")]
992        "12" => crate::operations::pumpfun_sell_interactive(&keypair, ops_language),
993        #[cfg(feature = "sol-trade-sdk")]
994        "13" => crate::operations::pumpswap_sell_interactive(&keypair, ops_language),
995        #[cfg(feature = "sol-trade-sdk")]
996        "14" => crate::operations::pumpfun_cashback_interactive(&keypair, ops_language),
997        #[cfg(feature = "sol-trade-sdk")]
998        "15" => crate::operations::pumpswap_cashback_interactive(&keypair, ops_language),
999        _ => Err("Invalid operation".to_string()),
1000    };
1001
1002    result
1003}
1004
1005/// Setup 2FA authentication interactively
1006#[cfg(feature = "2fa")]
1007fn setup_2fa_interactive(language: Language) -> Result<(), String> {
1008    use crate::{derive_totp_secret_from_hardware_and_password, hardware_fingerprint::HardwareFingerprint, security_question::SecurityQuestion, totp::*};
1009    use rpassword;
1010
1011    let account = "wallet";
1012    let issuer = "Sol-SafeKey";
1013
1014    println!("\n{}", "=".repeat(50).bright_magenta());
1015    if language == Language::Chinese {
1016        println!("{}", "  🔐 三因子 2FA 安全设置".bright_magenta().bold());
1017    } else {
1018        println!("{}", "  🔐 Triple-Factor 2FA Security Setup".bright_magenta().bold());
1019    }
1020    println!("{}", "=".repeat(50).bright_magenta());
1021    println!();
1022
1023    if language == Language::Chinese {
1024        println!("{}", "⚠️  安全架构说明:".yellow().bold());
1025        println!("  • 因子1: 硬件指纹(自动收集,绑定设备)");
1026        println!("  • 因子2: 主密码(您设置的强密码)");
1027        println!("  • 因子3: 安全问题答案(防止密码泄露)");
1028        println!("  • 2FA密钥: 从硬件指纹+主密码派生(确定性)");
1029        println!("  • 解锁需要: 主密码 + 安全问题答案 + 2FA动态验证码");
1030    } else {
1031        println!("{}", "⚠️  Security Architecture:".yellow().bold());
1032        println!("  • Factor 1: Hardware Fingerprint (auto-collected, device-bound)");
1033        println!("  • Factor 2: Master Password (your strong password)");
1034        println!("  • Factor 3: Security Question Answer (prevents password leak)");
1035        println!("  • 2FA Key: Derived from hardware fingerprint + master password");
1036        println!("  • Unlock requires: Master password + Security answer + 2FA code");
1037    }
1038    println!();
1039
1040    // Step 1: Collect hardware fingerprint
1041    if language == Language::Chinese {
1042        println!("{}", "步骤 1/4: 收集硬件指纹...".bright_blue());
1043    } else {
1044        println!("{}", "Step 1/4: Collecting hardware fingerprint...".bright_blue());
1045    }
1046
1047    let hardware_fp = HardwareFingerprint::collect()
1048        .map_err(|e| format!("Failed to collect hardware fingerprint: {}", e))?;
1049
1050    if language == Language::Chinese {
1051        println!("{} 硬件指纹已收集(SHA256哈希)", "✅".green());
1052        println!("   指纹预览: {}...", &hardware_fp.as_str()[..16]);
1053    } else {
1054        println!("{} Hardware fingerprint collected (SHA256 hash)", "✅".green());
1055        println!("   Preview: {}...", &hardware_fp.as_str()[..16]);
1056    }
1057    println!();
1058
1059    // Step 2: Set master password
1060    if language == Language::Chinese {
1061        println!("{}", "步骤 2/4: 设置主密码".bright_blue());
1062    } else {
1063        println!("{}", "Step 2/4: Set master password".bright_blue());
1064    }
1065
1066    let master_password = loop {
1067        let password = rpassword::prompt_password(
1068            if language == Language::Chinese { "请输入主密码: " } else { "Enter master password: " }
1069        ).map_err(|e| format!("Failed to read password: {}", e))?;
1070
1071        if password.is_empty() {
1072            println!("{} {}", "❌".red(), if language == Language::Chinese { "主密码不能为空" } else { "Master password cannot be empty" });
1073            continue;
1074        }
1075
1076        // Check password strength
1077        if password.len() < 10 {
1078            println!("{} {}", "❌".red(), if language == Language::Chinese { "密码长度至少10个字符" } else { "Password must be at least 10 characters" });
1079            continue;
1080        }
1081
1082        let password_confirm = rpassword::prompt_password(
1083            if language == Language::Chinese { "请再次输入主密码确认: " } else { "Confirm master password: " }
1084        ).map_err(|e| format!("Failed to read password: {}", e))?;
1085
1086        if password != password_confirm {
1087            println!("{} {}", "❌".red(), if language == Language::Chinese { "两次输入的密码不一致" } else { "Passwords do not match" });
1088            continue;
1089        }
1090
1091        break password;
1092    };
1093
1094    if language == Language::Chinese {
1095        println!("{} 主密码设置成功", "✅".green());
1096    } else {
1097        println!("{} Master password set successfully", "✅".green());
1098    }
1099    println!();
1100
1101    // Step 3: Set security question
1102    if language == Language::Chinese {
1103        println!("{}", "步骤 3/4: 设置安全问题".bright_blue());
1104    } else {
1105        println!("{}", "Step 3/4: Set security question".bright_blue());
1106    }
1107
1108    let (question_index, _security_answer) = SecurityQuestion::setup_interactive()
1109        .map_err(|e| format!("Failed to setup security question: {}", e))?;
1110    println!();
1111
1112    // Step 4: Setup 2FA
1113    if language == Language::Chinese {
1114        println!("{}", "步骤 4/4: 设置 2FA 动态验证码".bright_blue());
1115    } else {
1116        println!("{}", "Step 4/4: Setup 2FA TOTP".bright_blue());
1117    }
1118
1119    let twofa_secret = derive_totp_secret_from_hardware_and_password(
1120        hardware_fp.as_str(),
1121        &master_password,
1122        account,
1123        issuer,
1124    ).map_err(|e| format!("Failed to derive 2FA secret: {}", e))?;
1125
1126    let config = TOTPConfig {
1127        secret: twofa_secret.clone(),
1128        account: account.to_string(),
1129        issuer: issuer.to_string(),
1130        algorithm: "SHA1".to_string(),
1131        digits: 6,
1132        step: 30,
1133    };
1134
1135    let totp_manager = TOTPManager::new(config);
1136
1137    if language == Language::Chinese {
1138        println!("{}", "📱 请使用 Google Authenticator 或 Authy 扫描以下 QR 码:".yellow());
1139    } else {
1140        println!("{}", "📱 Scan this QR code with Google Authenticator or Authy:".yellow());
1141    }
1142    println!();
1143
1144    match totp_manager.generate_qr_code() {
1145        Ok(qr_code) => {
1146            println!("{}", qr_code);
1147        }
1148        Err(e) => {
1149            if language == Language::Chinese {
1150                eprintln!("{} QR 码生成失败: {}", "⚠️".yellow(), e);
1151                println!("{}", "📝 请手动输入以下信息:".yellow());
1152            } else {
1153                eprintln!("{} QR code generation failed: {}", "⚠️".yellow(), e);
1154                println!("{}", "📝 Please enter this info manually:".yellow());
1155            }
1156            println!("{}", totp_manager.get_manual_setup_info());
1157        }
1158    }
1159
1160    println!();
1161    if language == Language::Chinese {
1162        println!("{} 或者手动输入密钥: {}", "🔑".bright_cyan(), twofa_secret.bright_white());
1163    } else {
1164        println!("{} Or enter manually: {}", "🔑".bright_cyan(), twofa_secret.bright_white());
1165    }
1166    println!();
1167
1168    // Verify 2FA setup
1169    loop {
1170        print!("{}", if language == Language::Chinese {
1171            "请输入认证器显示的 6 位验证码以确认设置: "
1172        } else {
1173            "Enter the 6-digit code from your authenticator to verify: "
1174        });
1175        io::stdout().flush().map_err(|e| e.to_string())?;
1176
1177        let mut input = String::new();
1178        io::stdin().read_line(&mut input).map_err(|e| e.to_string())?;
1179        let code = input.trim();
1180
1181        match totp_manager.verify_code(code) {
1182            Ok(true) => {
1183                println!("{}", if language == Language::Chinese {
1184                    "✅ 2FA 验证成功!".green()
1185                } else {
1186                    "✅ 2FA verification successful!".green()
1187                });
1188                break;
1189            }
1190            Ok(false) => {
1191                println!("{}", if language == Language::Chinese {
1192                    "❌ 验证码不正确,请重试".red()
1193                } else {
1194                    "❌ Code incorrect, please try again".red()
1195                });
1196                continue;
1197            }
1198            Err(e) => {
1199                eprintln!("{} {}: {}", "❌".red(), if language == Language::Chinese { "验证失败" } else { "Verification failed" }, e);
1200                continue;
1201            }
1202        }
1203    }
1204
1205    println!();
1206    if language == Language::Chinese {
1207        println!("{}", "🎉 三因子 2FA 设置完成!".green().bold());
1208        println!();
1209        println!("{}", "📝 重要信息(请妥善保管):".yellow().bold());
1210        println!("  • 硬件指纹: 已绑定到当前设备");
1211        println!("  • 安全问题: 问题 {} - {}", question_index + 1, crate::security_question::SECURITY_QUESTIONS[question_index]);
1212        println!("  • 2FA密钥: 已添加到认证器");
1213        println!();
1214        println!("{}", "💡 下一步: 使用选项5生成三因子钱包".bright_blue());
1215    } else {
1216        println!("{}", "🎉 Triple-factor 2FA setup complete!".green().bold());
1217        println!();
1218        println!("{}", "📝 Important info (keep safe):".yellow().bold());
1219        println!("  • Hardware fingerprint: Bound to current device");
1220        println!("  • Security question: Question {} - {}", question_index + 1, crate::security_question::SECURITY_QUESTIONS[question_index]);
1221        println!("  • 2FA key: Added to authenticator");
1222        println!();
1223        println!("{}", "💡 Next step: Use option 5 to generate triple-factor wallet".bright_blue());
1224    }
1225
1226    Ok(())
1227}
1228
1229/// Generate triple-factor wallet interactively
1230#[cfg(feature = "2fa")]
1231fn generate_triple_factor_wallet_interactive(_language: Language) -> Result<(), String> {
1232    Err("This feature will be implemented soon. Please use CLI command: sol-safekey gen-2fa-wallet".to_string())
1233}
1234
1235/// Unlock triple-factor wallet interactively
1236#[cfg(feature = "2fa")]
1237fn unlock_triple_factor_wallet_interactive(_language: Language) -> Result<(), String> {
1238    Err("This feature will be implemented soon. Please use CLI command: sol-safekey unlock-2fa-wallet -f <file>".to_string())
1239}
1240
1241/// Read password with confirmation and validation
1242fn read_password_confirmed(texts: &Texts) -> Result<String, String> {
1243    println!("{}", texts.set_password);
1244
1245    let password = prompt_password(texts.new_password, texts)?;
1246
1247    if password.is_empty() {
1248        return Err(texts.password_empty.to_string());
1249    }
1250
1251    if password.len() < 10 {
1252        return Err(texts.password_min_length.to_string());
1253    }
1254
1255    let password_confirm = prompt_password(texts.confirm_password, texts)?;
1256
1257    if password != password_confirm {
1258        return Err(texts.password_mismatch.to_string());
1259    }
1260
1261    println!("{}", texts.password_set.green());
1262    Ok(password)
1263}