-
Notifications
You must be signed in to change notification settings - Fork 100
/
PrivateKeyStore.js
207 lines (184 loc) · 7.14 KB
/
PrivateKeyStore.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import Immutable from "immutable";
import alt from "../alt-instance";
import BaseStore from "./BaseStore";
import iDB from "../idb-instance";
import idb_helper from "../idb-helper";
import {PrivateKeyTcomb} from "./tcomb_structs";
import PrivateKeyActions from "actions/PrivateKeyActions"
import CachedPropertyActions from "actions/CachedPropertyActions"
import AddressIndex from "stores/AddressIndex"
import ChainStore from "api/ChainStore"
import PublicKey from "ecc/key_public"
import Address from "ecc/address"
import hash from "common/hash"
/** 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 extends BaseStore {
constructor() {
super()
this.state = this._getInitialState()
this.pending_operation_count = 0
this.bindListeners({
onLoadDbData: PrivateKeyActions.loadDbData,
onAddKey: PrivateKeyActions.addKey
})
this._export("hasKey", "getPubkeys", "getTcomb_byPubkey",
"getPubkeys_having_PrivateKey", "addPrivateKeys_noindex");
}
_getInitialState() {
return {
keys: Immutable.Map(),
privateKeyStorage_error: false,
pending_operation_count: 0,
privateKeyStorage_error_add_key: null,
privateKeyStorage_error_loading: null
}
}
/** This method may be called again should the main database change */
onLoadDbData(resolve) {//resolve is deprecated
this.pendingOperation()
this.setState(this._getInitialState())
var keys = Immutable.Map().asMutable()
var p = idb_helper.cursor("private_keys", cursor => {
if( ! cursor) {
this.setState({ keys: keys.asImmutable() })
return
}
var 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.setState(this._getInitialState())
this.privateKeyStorageError('loading', error)
throw error
})
resolve( p )
}
hasKey(pubkey) {
return this.state.keys.has(pubkey)
}
getPubkeys() {
console.log("getPubkeys", this.state.keys.keySeq().toArray())
return this.state.keys.keySeq().toArray()
}
getPubkeys_having_PrivateKey(pubkeys, addys = null) {
var return_pubkeys = []
if(pubkeys) {
for(let pubkey of pubkeys) {
if(this.hasKey(pubkey)) {
return_pubkeys.push(pubkey)
}
}
}
if(addys) {
var addresses = AddressIndex.getState().addresses
for (let addy of addys) {
var 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}) {// resolve is deprecated
if(this.state.keys.has(private_key_object.pubkey)) {
resolve({result:"duplicate",id:null})
return
}
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})
AddressIndex.add(private_key_object.pubkey)
var p = new Promise((resolve, reject) => {
PrivateKeyTcomb(private_key_object)
var duplicate = false
var p = idb_helper.add(
transaction.objectStore("private_keys"),
private_key_object
).catch( event => {
// ignore_duplicates
var 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.setState({ keys: this.state.keys }) } )
return {
result: "added",
id: private_key_object.id
}
})
resolve(p)
})
resolve(p)
}
/** WARN: does not update AddressIndex. This is designed for bulk importing.
@return duplicate_count
*/
addPrivateKeys_noindex(private_key_objects, transaction) {
var store = transaction.objectStore("private_keys")
var duplicate_count = 0
var 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
}
var 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.setState({ keys })
this.binaryBackupRecommended()
return duplicate_count
}
binaryBackupRecommended() {
CachedPropertyActions.set("backup_recommended", true)
}
pendingOperation() {
this.pending_operation_count++
this.setState({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.setState({pending_operation_count: this.pending_operation_count})
}
privateKeyStorageError(property, error) {
this.pendingOperationDone()
var state = { privateKeyStorage_error: true }
state["privateKeyStorage_error_" + property] = error
console.error("privateKeyStorage_error_" + property, error)
this.setState(state)
}
}
module.exports = alt.createStore(PrivateKeyStore, "PrivateKeyStore");