dev
dart 132 lines 4.58 KB
Raw
1 import 'dart:convert';
2 import 'dart:developer' as dev;
3 import 'dart:io';
4
5 import 'package:cw_core/balance.dart';
6 import 'package:cw_core/encryption_file_utils.dart';
7 import 'package:cw_core/pathForWallet.dart';
8 import 'package:cw_core/transaction_history.dart';
9 import 'package:cw_core/transaction_info.dart';
10 import 'package:cw_core/wallet_base.dart';
11 import 'package:cw_core/wallet_type.dart';
12
13 mixin WalletKeysFile<BalanceType extends Balance, HistoryType extends TransactionHistoryBase,
14 TransactionType extends TransactionInfo>
15 on WalletBase<BalanceType, HistoryType, TransactionType> {
16 Future<String> makePath() => pathForWallet(name: walletInfo.name, type: walletInfo.type);
17
18 // this needs to be overridden
19 WalletKeysData get walletKeysData;
20
21 Future<String> makeKeysFilePath() async => "${await makePath()}.keys";
22
23 Future<void> saveKeysFile(String password, EncryptionFileUtils encryptionFileUtils,
24 [bool isBackup = false]) async {
25 try {
26 final rootPath = await makeKeysFilePath();
27 final path = "$rootPath${isBackup ? ".backup" : ""}";
28 dev.log("Saving .keys file '$path'");
29 await encryptionFileUtils.write(
30 path: path, password: password, data: walletKeysData.toJSON());
31 } catch (_) {}
32 }
33
34 static Future<void> createKeysFile(String name, WalletType type, String password,
35 WalletKeysData walletKeysData, EncryptionFileUtils encryptionFileUtils,
36 [bool withBackup = true]) async {
37 try {
38 final rootPath = await pathForWallet(name: name, type: type);
39 final path = "$rootPath.keys";
40
41 dev.log("Saving .keys file '$path'");
42 await encryptionFileUtils.write(
43 path: path, password: password, data: walletKeysData.toJSON());
44
45 if (withBackup) {
46 dev.log("Saving .keys.backup file '$path.backup'");
47 await encryptionFileUtils.write(
48 path: "$path.backup", password: password, data: walletKeysData.toJSON());
49 }
50 } catch (_) {}
51 }
52
53 static Future<bool> hasKeysFile(String name, WalletType type) async {
54 try {
55 final path = await pathForWallet(name: name, type: type);
56 return File("$path.keys").existsSync() || File("$path.keys.backup").existsSync();
57 } catch (_) {
58 return false;
59 }
60 }
61
62 static Future<WalletKeysData> readKeysFile(
63 String name,
64 WalletType type,
65 String password,
66 EncryptionFileUtils encryptionFileUtils,
67 ) async {
68 final path = await pathForWallet(name: name, type: type);
69
70 var readPath = "$path.keys";
71 try {
72 if (!File(readPath).existsSync()) throw Exception("No .keys file found for $name $type");
73
74 final jsonSource = await encryptionFileUtils.read(path: readPath, password: password);
75 final data = json.decode(jsonSource) as Map<String, dynamic>;
76 return WalletKeysData.fromJSON(data);
77 } catch (e) {
78 dev.log("Failed to read .keys file. Trying .keys.backup file...");
79
80 readPath = "$readPath.backup";
81 if (!File(readPath).existsSync())
82 throw Exception("No .keys nor a .keys.backup file found for $name $type");
83
84 final jsonSource = await encryptionFileUtils.read(path: readPath, password: password);
85 final data = json.decode(jsonSource) as Map<String, dynamic>;
86 final keysData = WalletKeysData.fromJSON(data);
87
88 dev.log("Restoring .keys from .keys.backup");
89 createKeysFile(name, type, password, keysData, encryptionFileUtils, false);
90 return keysData;
91 }
92 }
93 }
94
95 class WalletKeysData {
96 final String? privateKey;
97 final String? mnemonic;
98 final String? altMnemonic;
99 final String? passphrase;
100 final String? xPub;
101 final String? scanSecret;
102 final String? spendPubkey;
103
104 WalletKeysData(
105 {this.privateKey,
106 this.mnemonic,
107 this.altMnemonic,
108 this.passphrase,
109 this.xPub,
110 this.scanSecret,
111 this.spendPubkey});
112
113 String toJSON() => jsonEncode({
114 "privateKey": privateKey,
115 "mnemonic": mnemonic,
116 if (altMnemonic != null) "altMnemonic": altMnemonic,
117 if (passphrase != null) "passphrase": passphrase,
118 if (xPub != null) "xPub": xPub,
119 if (scanSecret != null) "scanSecret": scanSecret,
120 if (spendPubkey != null) "spendPubkey": spendPubkey,
121 });
122
123 static WalletKeysData fromJSON(Map<String, dynamic> json) => WalletKeysData(
124 privateKey: json["privateKey"] as String?,
125 mnemonic: json["mnemonic"] as String?,
126 altMnemonic: json["altMnemonic"] as String?,
127 passphrase: json["passphrase"] as String?,
128 xPub: json["xPub"] as String?,
129 scanSecret: json["scanSecret"] as String?,
130 spendPubkey: json["spendPubkey"] as String?,
131 );
132 }