UNPKG

newpay-wallet-js

Version:

287 lines (253 loc) 9.5 kB
import Immutable from "immutable"; import idb_helper from "./idb-helper.js"; import WalletDb from "./WalletDb.js"; import {PrivateKeyTcomb} from "./tcomb_structs"; //import PrivateKeyActions from "./PrivateKeyActions.js"; //import CachedPropertyActions from "./CachedPropertyActions.js"; import AddressIndex from "./AddressIndex.js"; import {PublicKey, ChainStore, Aes} from "bitsharesjs/es"; import {clone} from "lodash"; /** No need to wait on the promises returned by this store as long as this.state.privateKeyStorage_error == false and this.state.pending_operation_count == 0 before performing any important operations. */ class PrivateKeyStore { constructor() { this.state = this._getInitialState(); this.pending_operation_count = 0; /* cyj delete 20171023 this.bindListeners({ onLoadDbData: PrivateKeyActions.loadDbData, onAddKey: PrivateKeyActions.addKey }); */ } static getInstance() { if (!PrivateKeyStore.instance) { PrivateKeyStore.instance = new PrivateKeyStore(); } return PrivateKeyStore.instance; } _getInitialState() { return { keys: Immutable.Map(), privateKeyStorage_error: false, pending_operation_count: 0, privateKeyStorage_error_add_key: null, privateKeyStorage_error_loading: null }; } getState(){ return clone( this.state,false ); } setPasswordLoginKey(key) { let keys = this.state.keys.set(key.pubkey, key); this.state.keys = keys; } //将表private_keys的value列的数据中的pubkey存到AddressIndex中. /** This method may be called again should the main database change */ onLoadDbData() {//resolve is deprecated this.pendingOperation(); this.state = this._getInitialState(); let keys = Immutable.Map().asMutable(); let p = idb_helper.cursor("private_keys", cursor => { if( ! cursor) { this.state.keys = keys.asImmutable(); return; } let private_key_tcomb = PrivateKeyTcomb(cursor.value); keys.set(private_key_tcomb.pubkey, private_key_tcomb); AddressIndex.add(private_key_tcomb.pubkey); cursor.continue(); }).then(()=>{ this.pendingOperationDone(); }).catch( error => { this.state = this._getInitialState(); this.privateKeyStorageError("loading", error); throw error; }); return p ; } hasKey(pubkey) { return this.state.keys.has(pubkey); } getPubkeys() { return this.state.keys.keySeq().toArray(); } getPubkeys_having_PrivateKey(pubkeys, addys = null) { let return_pubkeys = []; if(pubkeys) { for(let pubkey of pubkeys) { if(this.hasKey(pubkey)) { return_pubkeys.push(pubkey); } } } if(addys) { let addresses = AddressIndex.getState().addresses; for (let addy of addys) { let pubkey = addresses.get(addy); return_pubkeys.push(pubkey); } } return return_pubkeys; } getTcomb_byPubkey(public_key) { if(! public_key) return null; if(public_key.Q) public_key = public_key.toPublicKeyString(); return this.state.keys.get(public_key); } onAddKey({private_key_object, transaction}) {// resolve is deprecated if(this.state.keys.has(private_key_object.pubkey)) { return({result:"duplicate",id:null}); } this.pendingOperation(); //console.log("... onAddKey private_key_object.pubkey", private_key_object.pubkey) this.state.keys = this.state.keys.set( private_key_object.pubkey, PrivateKeyTcomb(private_key_object) ); //this.setState({keys: this.state.keys}); this.state.keys = this.state.keys; AddressIndex.add(private_key_object.pubkey); let p = new Promise((resolve, reject) => { PrivateKeyTcomb(private_key_object); let duplicate = false; let p = idb_helper.add( transaction.objectStore("private_keys"), private_key_object ); p.catch( event => { // ignore_duplicates let error = event.target.error; console.log("... error", error, event); if( error.name != "ConstraintError" || error.message.indexOf("by_encrypted_key") == -1 ) { this.privateKeyStorageError("add_key", error); throw event; } duplicate = true; event.preventDefault(); }).then( ()=> { this.pendingOperationDone(); if(duplicate) return {result:"duplicate",id:null}; if( private_key_object.brainkey_sequence == null) this.binaryBackupRecommended(); // non-deterministic idb_helper.on_transaction_end(transaction).then( () => { this.state.keys = this.state.keys; } ); return { result: "added", id: private_key_object.id }; }); resolve(p); }); return p; } /** WARN: does not update AddressIndex. This is designed for bulk importing. @return duplicate_count */ addPrivateKeys_noindex(private_key_objects, transaction) { let store = transaction.objectStore("private_keys"); let duplicate_count = 0; let keys = this.state.keys.withMutations( keys => { for(let private_key_object of private_key_objects) { if(this.state.keys.has(private_key_object.pubkey)) { duplicate_count++; continue; } let private_tcomb = PrivateKeyTcomb(private_key_object); store.add( private_key_object ); keys.set( private_key_object.pubkey, private_tcomb ); ChainStore.getAccountRefsOfKey(private_key_object.pubkey); } }); this.state.keys = keys; this.binaryBackupRecommended(); return duplicate_count; } //脑钥备份 cyj delete 暂时用不到 /* binaryBackupRecommended() { CachedPropertyActions.set("backup_recommended", true); } */ pendingOperation() { this.pending_operation_count++; this.state.pending_operation_count = this.pending_operation_count; } pendingOperationDone() { if(this.pending_operation_count == 0) throw new Error("Pending operation done called too many times"); this.pending_operation_count--; this.state.pending_operation_count = this.pending_operation_count; } privateKeyStorageError(property, error) { this.pendingOperationDone(); let state = { privateKeyStorage_error: true }; state["privateKeyStorage_error_" + property] = error; console.error("privateKeyStorage_error_" + property, error); this.state = state; } decodeMemo(memo) { let lockedWallet = false; let memo_text, isMine = false; let from_private_key = this.state.keys.get(memo.from); let to_private_key = this.state.keys.get(memo.to); let private_key = from_private_key ? from_private_key : to_private_key; let public_key = from_private_key ? memo.to : memo.from; public_key = PublicKey.fromPublicKeyString(public_key); try { private_key = WalletDb.decryptTcomb_PrivateKey(private_key); } catch(e) { // Failed because wallet is locked lockedWallet = true; private_key = null; isMine = true; } if (private_key) { let tryLegacy = false; try { memo_text = private_key ? Aes.decrypt_with_checksum( private_key, public_key, memo.nonce, memo.message ).toString("utf-8") : null; if (private_key && !memo_text) { // debugger } } catch(e) { console.log("transfer memo exception ...", e); memo_text = "*"; tryLegacy = true; } // Apply legacy method if new, correct method fails to decode if (private_key && tryLegacy) { // debugger; try { memo_text = Aes.decrypt_with_checksum( private_key, public_key, memo.nonce, memo.message, true ).toString("utf-8"); } catch(e) { console.log("transfer memo exception ...", e); memo_text = "**"; } } } return { text: memo_text, isMine }; } } var PrivateKeyStoreIns = PrivateKeyStore.getInstance(); export default PrivateKeyStoreIns;