keyring.dart 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import 'dart:async';
  2. import 'dart:convert';
  3. import 'package:polkawallet_sdk/api/apiKeyring.dart';
  4. import 'package:polkawallet_sdk/api/types/addressIconData.dart';
  5. import 'package:polkawallet_sdk/service/index.dart';
  6. import 'package:polkawallet_sdk/storage/keyring.dart';
  7. class ServiceKeyring {
  8. ServiceKeyring(this.serviceRoot);
  9. final SubstrateService serviceRoot;
  10. Future<Map?> getPubKeyAddressMap(List keyPairs, List<int> ss58) async {
  11. final List<String> pubKeys =
  12. keyPairs.map((e) => e['pubKey'].toString()).toList();
  13. return await serviceRoot.account.encodeAddress(pubKeys, ss58);
  14. }
  15. Future<List?> getPubKeyIconsMap(List<String?> pubKeys) async {
  16. return await serviceRoot.account.getPubKeyIcons(pubKeys);
  17. }
  18. Future<Map?> injectKeyPairsToWebView(Keyring keyring) async {
  19. final resMap = Map<String, Map>();
  20. if (keyring.store.list.length > 0) {
  21. final String pairs = jsonEncode(keyring.store.list);
  22. final ss58 = keyring.store.ss58List;
  23. final res = Map<String, Map>.from(await serviceRoot.webView!
  24. .evalJavascript('keyring.initKeys($pairs, ${jsonEncode(ss58)})'));
  25. resMap.addAll(res);
  26. }
  27. if (keyring.store.contacts.length > 0) {
  28. final ss58 = keyring.store.ss58List;
  29. final contacts = await getPubKeyAddressMap(keyring.store.contacts, ss58);
  30. if (resMap.length > 0) {
  31. resMap.forEach((key, value) {
  32. resMap[key]!.addAll(contacts![key]);
  33. });
  34. } else {
  35. contacts!.forEach((key, value) {
  36. resMap[key] = value;
  37. });
  38. }
  39. }
  40. if (resMap.length > 0) {
  41. keyring.store.updatePubKeyAddressMap(resMap);
  42. return resMap;
  43. }
  44. return null;
  45. }
  46. Map updateKeyPairMetaData(Map acc, String? name) {
  47. acc['name'] = name;
  48. acc['meta']['name'] = name;
  49. if (acc['meta']['whenCreated'] == null) {
  50. acc['meta']['whenCreated'] = DateTime.now().millisecondsSinceEpoch;
  51. }
  52. acc['meta']['whenEdited'] = DateTime.now().millisecondsSinceEpoch;
  53. return acc;
  54. }
  55. /// Generate a set of new mnemonic.
  56. Future<AddressIconDataWithMnemonic> generateMnemonic(int ss58,
  57. {CryptoType cryptoType = CryptoType.sr25519,
  58. String derivePath = '',
  59. String key = ''}) async {
  60. final String crypto = cryptoType.toString().split('.')[1];
  61. final isAvatarSupport = (await serviceRoot.webView!.evalJavascript(
  62. 'keyring.addressFromMnemonic ? {}:null',
  63. wrapPromise: false)) !=
  64. null;
  65. final dynamic acc = await serviceRoot.webView!.evalJavascript(
  66. isAvatarSupport
  67. ? 'keyring.gen("$key",$ss58,"$crypto","$derivePath")'
  68. : 'keyring.gen()');
  69. return AddressIconDataWithMnemonic.fromJson(acc);
  70. }
  71. /// get address and avatar from mnemonic.
  72. Future<AddressIconData> addressFromMnemonic(int ss58,
  73. {CryptoType cryptoType = CryptoType.sr25519,
  74. String derivePath = '',
  75. required String mnemonic}) async {
  76. final String crypto = cryptoType.toString().split('.')[1];
  77. final isAvatarSupport = (await serviceRoot.webView!.evalJavascript(
  78. 'keyring.addressFromMnemonic ? {}:null',
  79. wrapPromise: false)) !=
  80. null;
  81. final dynamic acc = isAvatarSupport
  82. ? (await serviceRoot.webView!.evalJavascript(
  83. 'keyring.addressFromMnemonic("$mnemonic",$ss58,"$crypto","$derivePath")'))
  84. : {};
  85. return AddressIconData.fromJson(Map<String, dynamic>.from(acc));
  86. }
  87. /// get address and avatar from rawSeed.
  88. Future<AddressIconData> addressFromRawSeed(int ss58,
  89. {CryptoType cryptoType = CryptoType.sr25519,
  90. String derivePath = '',
  91. required String rawSeed}) async {
  92. final String crypto = cryptoType.toString().split('.')[1];
  93. final isAvatarSupport = (await serviceRoot.webView!.evalJavascript(
  94. 'keyring.addressFromMnemonic ? {}:null',
  95. wrapPromise: false)) !=
  96. null;
  97. final dynamic acc = isAvatarSupport
  98. ? (await serviceRoot.webView!.evalJavascript(
  99. 'keyring.addressFromRawSeed("$rawSeed",$ss58,"$crypto","$derivePath")'))
  100. : {};
  101. return AddressIconData.fromJson(Map<String, dynamic>.from(acc));
  102. }
  103. /// get address and avatar from KeyStore.
  104. Future<dynamic> addressFromKeyStore(int ss58, {required Map keyStore}) async {
  105. final String addressOld = keyStore['address'];
  106. final dynamic acc = await serviceRoot.webView!
  107. .evalJavascript('account.decodeAddress(["$addressOld"])'
  108. '.then(res => account.encodeAddress(Object.keys(res), [$ss58]))'
  109. '.then(res => account.genIcons(Object.values(res[$ss58])))');
  110. return acc;
  111. }
  112. /// check mnemonic valid.
  113. Future<bool> checkMnemonicValid(String mnemonic) async {
  114. final isApiSupport = (await serviceRoot.webView!.evalJavascript(
  115. 'keyring.checkMnemonicValid ? {}:null',
  116. wrapPromise: false)) !=
  117. null;
  118. final bool res = isApiSupport
  119. ? (await serviceRoot.webView!
  120. .evalJavascript('keyring.checkMnemonicValid("$mnemonic")'))
  121. : true;
  122. return res;
  123. }
  124. /// Import account from mnemonic/rawSeed/keystore.
  125. /// param [cryptoType] can be `sr25519`(default) or `ed25519`.
  126. /// return [null] if import failed.
  127. Future<dynamic> importAccount({
  128. required KeyType keyType,
  129. required String key,
  130. required name,
  131. required password,
  132. CryptoType cryptoType = CryptoType.sr25519,
  133. String derivePath = '',
  134. }) async {
  135. // generate json from js-api
  136. final String type = keyType.toString().split('.')[1];
  137. final String crypto = cryptoType.toString().split('.')[1];
  138. String code =
  139. 'keyring.recover("$type", "$crypto", \'$key$derivePath\', "$password")';
  140. code = code.replaceAll(RegExp(r'\t|\n|\r'), '');
  141. final dynamic acc = await serviceRoot.webView!.evalJavascript(code);
  142. if (acc == null || acc['error'] != null) {
  143. return acc;
  144. }
  145. // add metadata to json
  146. updateKeyPairMetaData(acc, name);
  147. return acc;
  148. }
  149. /// check password of account
  150. Future<bool> checkPassword(String? pubKey, pass) async {
  151. final res = await serviceRoot.webView!
  152. .evalJavascript('keyring.checkPassword("$pubKey", "$pass")');
  153. if (res == null) {
  154. return false;
  155. }
  156. return true;
  157. }
  158. /// change password of account
  159. Future<Map?> changePassword(String? pubKey, passOld, passNew) async {
  160. final res = await serviceRoot.webView!.evalJavascript(
  161. 'keyring.changePassword("$pubKey", "$passOld", "$passNew")');
  162. return res;
  163. }
  164. Future<String?> checkDerivePath(
  165. String seed, path, CryptoType cryptoType) async {
  166. final String crypto = cryptoType.toString().split('.')[1];
  167. dynamic res = await serviceRoot.webView!
  168. .evalJavascript('keyring.checkDerivePath("$seed", "$path", "$crypto")');
  169. return res;
  170. }
  171. Future<Map?> signAsExtension(String password, Map args) async {
  172. final String call = args['msgType'] == 'pub(bytes.sign)'
  173. ? 'signBytesAsExtension'
  174. : 'signTxAsExtension';
  175. final res = await serviceRoot.webView!.evalJavascript(
  176. 'keyring.$call("$password", ${jsonEncode(args['request'])})',
  177. allowRepeat: true,
  178. );
  179. return res;
  180. }
  181. Future<Map?> signatureVerify(String message, signature, address) async {
  182. final res = await serviceRoot.webView!.evalJavascript(
  183. 'keyring.verifySignature("$message", "$signature", "$address")',
  184. allowRepeat: true,
  185. );
  186. if (res == null) {
  187. return null;
  188. }
  189. return res;
  190. }
  191. }