return new Promise( (resolve, reject) => { if( typeof password_plaintext !== 'string') throw new Error("password string is required") var brainkey_backup_date if(brainkey_plaintext) { if(typeof brainkey_plaintext !== "string") throw new Error("Brainkey must be a string") if(brainkey_plaintext.trim() === "") throw new Error("Brainkey can not be an empty string") if(brainkey_plaintext.length < 50) throw new Error("Brainkey must be at least 50 characters long") // The user just provided the Brainkey so this avoids // bugging them to back it up again. brainkey_backup_date = new Date() } var password_aes = Aes.fromSeed( password_plaintext ) var encryption_buffer = key.get_random_key().toBuffer() // encryption_key is the global encryption key (does not change even if the passsword changes) var encryption_key = password_aes.encryptToHex( encryption_buffer ) // If unlocking, local_aes_private will become the global aes_private object var local_aes_private = Aes.fromSeed( encryption_buffer ) if( ! brainkey_plaintext) brainkey_plaintext = key.suggest_brain_key(dictionary.en) else brainkey_plaintext = key.normalize_brainKey(brainkey_plaintext) var brainkey_private = this.getBrainKeyPrivate( brainkey_plaintext ) var brainkey_pubkey = brainkey_private.toPublicKey().toPublicKeyString() var encrypted_brainkey = local_aes_private.encryptToHex( brainkey_plaintext ) var password_private = PrivateKey.fromSeed( password_plaintext ) var password_pubkey = password_private.toPublicKey().toPublicKeyString() let wallet = { public_name, password_pubkey, encryption_key, encrypted_brainkey, brainkey_pubkey, brainkey_sequence: 0, brainkey_backup_date, created: new Date(), last_modified: new Date(), chain_id: Apis.instance().chain_id } WalletTcomb(wallet) // validation var transaction = this.transaction_update() var add = idb_helper.add( transaction.objectStore("wallet"), wallet ) var end = idb_helper.on_transaction_end(transaction).then( () => { this.state.wallet = wallet this.setState({ wallet }) if(unlock) aes_private = local_aes_private }) resolve( Promise.all([ add, end ]) ) })
this.init(()=> { try { initalizing = false status({ initalizing }) var running_count_progress = 1 for(var a = 0; a < account_keys.length; a++) { var removed_count = 0, count = 0 var keys = account_keys[a] var total = keys.encrypted_private_keys.length status({ importing: true, account_name: keys.account_name, count, total }) for(var k = keys.encrypted_private_keys.length - 1; k >= 0; k--) { count++ if( count % running_count_progress === 0 ) { running_count_progress = 47 status({ importing: true, account_name: keys.account_name, count, total }) } if( ! keys.public_keys) { // un-released format, just for testing status({ error: "missing_public_keys" }) return } var key = keys.public_keys[k] if( /^GPH/.test(key) ) key = "BTS" + key.substring(3) if(this.inGenesis( key )) continue var addresses = key.addresses(key, 'BTS') var addy_found = false for(var i = 0; i < addresses.length; i++) { if(this.inGenesis( addresses[i] )) { addy_found = true break } } if( addy_found ) continue delete keys.encrypted_private_keys[k] delete keys.public_keys[k] removed_count++ } var encrypted_private_keys = [], public_keys = [] for(var k = keys.encrypted_private_keys.length - 1; k >= 0; k--) { if( ! keys.encrypted_private_keys[k]) continue encrypted_private_keys.push( keys.encrypted_private_keys[k] ) public_keys.push( keys.public_keys[k] ) } keys.encrypted_private_keys = encrypted_private_keys status({ importing: false, account_name: keys.account_name, count: count - removed_count, total }) keys.public_keys = public_keys } status({ success: true, }) } finally { if( initalizing ) { initalizing = false status({ initalizing }) } } })
indexPubkey(pubkey) { for(let address_string of key.addresses(pubkey)) { if( !this.no_balance_address.has(address_string)) { // AddressIndex indexes all addresses .. Here only 1 address is involved this.state.address_to_pubkey.set(address_string, pubkey) this.addresses.add(address_string) } } this.setState({address_to_pubkey: this.state.address_to_pubkey}) }
/** @throws "missing brainkey", "wallet locked" @return { private_key, sequence } */ generateNextKey(save = true) { var brainkey = this.getBrainKey() var wallet = this.state.wallet var sequence = wallet.brainkey_sequence var used_sequence = null // Skip ahead in the sequence if any keys are found in use // Slowly look ahead (1 new key per block) to keep the wallet fast after unlocking this.brainkey_look_ahead = Math.min(10, (this.brainkey_look_ahead||0) + 1) for (var i = sequence; i < sequence + this.brainkey_look_ahead; i++) { var private_key = key.get_brainPrivateKey( brainkey, i ) var pubkey = this.generateNextKey_pubcache[i] ? this.generateNextKey_pubcache[i] : this.generateNextKey_pubcache[i] = private_key.toPublicKey().toPublicKeyString() var next_key = ChainStore.getAccountRefsOfKey( pubkey ) // TODO if ( next_key === undefined ) return undefined if(next_key && next_key.size) { used_sequence = i console.log("WARN: Private key sequence " + used_sequence + " in-use. " + "I am saving the private key and will go onto the next one.") this.saveKey( private_key, used_sequence ) } } if(used_sequence !== null) { wallet.brainkey_sequence = used_sequence + 1 this._updateWallet() } sequence = wallet.brainkey_sequence var private_key = key.get_brainPrivateKey( brainkey, sequence ) if( save ) { // save deterministic private keys ( the user can delete the brainkey ) this.saveKey( private_key, sequence ) //TODO .error( error => ErrorStore.onAdd( "wallet", "saveKey", error )) this.incrementBrainKeySequence() } return { private_key, sequence } }
return new Promise( resolve => { var public_key = PublicKey.fromPublicKeyString(backup_pubkey) var onetime_private_key = key.get_random_key(entropy) var walletString = JSON.stringify(wallet_object, null, 0) compress(walletString, compression_mode, compressedWalletBytes => { var backup_buffer = Aes.encrypt_with_checksum(onetime_private_key, public_key, null/*nonce*/, compressedWalletBytes) var onetime_public_key = onetime_private_key.toPublicKey() var backup = Buffer.concat([ onetime_public_key.toBuffer(), backup_buffer ]) resolve(backup) }) })
onmessage = function(event) { try { console.log("AddressIndexWorker start"); var {pubkeys, address_prefix} = event.data var results = [] for (let pubkey of pubkeys) { results.push( key.addresses(pubkey, address_prefix) ) } postMessage( results ) console.log("AddressIndexWorker done"); } catch( e ) { console.error("AddressIndexWorker", e) } }
getBrainKeyPrivate(brainkey_plaintext = this.getBrainKey()) { if( ! brainkey_plaintext) throw new Error("missing brainkey") return PrivateKey.fromSeed( key.normalize_brainKey(brainkey_plaintext) ) }