diff options
Diffstat (limited to 'src/js/index.js')
-rw-r--r-- | src/js/index.js | 109 |
1 files changed, 95 insertions, 14 deletions
diff --git a/src/js/index.js b/src/js/index.js index f3582b0..8f7d658 100644 --- a/src/js/index.js +++ b/src/js/index.js | |||
@@ -12,6 +12,7 @@ | |||
12 | var showPrivKey = true; | 12 | var showPrivKey = true; |
13 | 13 | ||
14 | var phraseChangeTimeoutEvent = null; | 14 | var phraseChangeTimeoutEvent = null; |
15 | var rootKeyChangedTimeoutEvent = null; | ||
15 | 16 | ||
16 | var DOM = {}; | 17 | var DOM = {}; |
17 | DOM.network = $(".network"); | 18 | DOM.network = $(".network"); |
@@ -34,6 +35,7 @@ | |||
34 | DOM.bip44account = $("#bip44 .account"); | 35 | DOM.bip44account = $("#bip44 .account"); |
35 | DOM.bip44change = $("#bip44 .change"); | 36 | DOM.bip44change = $("#bip44 .change"); |
36 | DOM.strength = $(".strength"); | 37 | DOM.strength = $(".strength"); |
38 | DOM.hardenedAddresses = $(".hardened-addresses"); | ||
37 | DOM.addresses = $(".addresses"); | 39 | DOM.addresses = $(".addresses"); |
38 | DOM.rowsToAdd = $(".rows-to-add"); | 40 | DOM.rowsToAdd = $(".rows-to-add"); |
39 | DOM.more = $(".more"); | 41 | DOM.more = $(".more"); |
@@ -50,12 +52,14 @@ | |||
50 | DOM.passphrase.on("input", delayedPhraseChanged); | 52 | DOM.passphrase.on("input", delayedPhraseChanged); |
51 | DOM.generate.on("click", generateClicked); | 53 | DOM.generate.on("click", generateClicked); |
52 | DOM.more.on("click", showMore); | 54 | DOM.more.on("click", showMore); |
53 | DOM.bip32path.on("input", delayedPhraseChanged); | 55 | DOM.rootKey.on("input", delayedRootKeyChanged); |
54 | DOM.bip44purpose.on("input", delayedPhraseChanged); | 56 | DOM.bip32path.on("input", calcForDerivationPath); |
55 | DOM.bip44coin.on("input", delayedPhraseChanged); | 57 | DOM.bip44purpose.on("input", calcForDerivationPath); |
56 | DOM.bip44account.on("input", delayedPhraseChanged); | 58 | DOM.bip44coin.on("input", calcForDerivationPath); |
57 | DOM.bip44change.on("input", delayedPhraseChanged); | 59 | DOM.bip44account.on("input", calcForDerivationPath); |
58 | DOM.tab.on("click", delayedPhraseChanged); | 60 | DOM.bip44change.on("input", calcForDerivationPath); |
61 | DOM.tab.on("shown.bs.tab", calcForDerivationPath); | ||
62 | DOM.hardenedAddresses.on("change", calcForDerivationPath); | ||
59 | DOM.indexToggle.on("click", toggleIndexes); | 63 | DOM.indexToggle.on("click", toggleIndexes); |
60 | DOM.addressToggle.on("click", toggleAddresses); | 64 | DOM.addressToggle.on("click", toggleAddresses); |
61 | DOM.privateKeyToggle.on("click", togglePrivateKeys); | 65 | DOM.privateKeyToggle.on("click", togglePrivateKeys); |
@@ -68,9 +72,14 @@ | |||
68 | // Event handlers | 72 | // Event handlers |
69 | 73 | ||
70 | function networkChanged(e) { | 74 | function networkChanged(e) { |
71 | var network = e.target.value; | 75 | var networkIndex = e.target.value; |
72 | networks[network].onSelect(); | 76 | networks[networkIndex].onSelect(); |
73 | delayedPhraseChanged(); | 77 | if (seed != null) { |
78 | phraseChanged(); | ||
79 | } | ||
80 | else { | ||
81 | rootKeyChanged(); | ||
82 | } | ||
74 | } | 83 | } |
75 | 84 | ||
76 | function delayedPhraseChanged() { | 85 | function delayedPhraseChanged() { |
@@ -87,12 +96,57 @@ | |||
87 | hideValidationError(); | 96 | hideValidationError(); |
88 | // Get the mnemonic phrase | 97 | // Get the mnemonic phrase |
89 | var phrase = DOM.phrase.val(); | 98 | var phrase = DOM.phrase.val(); |
90 | var passphrase = DOM.passphrase.val(); | ||
91 | var errorText = findPhraseErrors(phrase); | 99 | var errorText = findPhraseErrors(phrase); |
92 | if (errorText) { | 100 | if (errorText) { |
93 | showValidationError(errorText); | 101 | showValidationError(errorText); |
94 | return; | 102 | return; |
95 | } | 103 | } |
104 | // Calculate and display | ||
105 | var passphrase = DOM.passphrase.val(); | ||
106 | calcBip32RootKeyFromSeed(phrase, passphrase); | ||
107 | calcForDerivationPath(); | ||
108 | hidePending(); | ||
109 | } | ||
110 | |||
111 | function delayedRootKeyChanged() { | ||
112 | // Warn if there is an existing mnemonic or passphrase. | ||
113 | if (DOM.phrase.val().length > 0 || DOM.passphrase.val().length > 0) { | ||
114 | if (!confirm("This will clear existing mnemonic and passphrase")) { | ||
115 | DOM.rootKey.val(bip32RootKey); | ||
116 | return | ||
117 | } | ||
118 | } | ||
119 | hideValidationError(); | ||
120 | showPending(); | ||
121 | // Clear existing mnemonic and passphrase | ||
122 | DOM.phrase.val(""); | ||
123 | DOM.passphrase.val(""); | ||
124 | seed = null; | ||
125 | if (rootKeyChangedTimeoutEvent != null) { | ||
126 | clearTimeout(rootKeyChangedTimeoutEvent); | ||
127 | } | ||
128 | rootKeyChangedTimeoutEvent = setTimeout(rootKeyChanged, 400); | ||
129 | } | ||
130 | |||
131 | function rootKeyChanged() { | ||
132 | showPending(); | ||
133 | hideValidationError(); | ||
134 | // Validate the root key TODO | ||
135 | var rootKeyBase58 = DOM.rootKey.val(); | ||
136 | var errorText = validateRootKey(rootKeyBase58); | ||
137 | if (errorText) { | ||
138 | showValidationError(errorText); | ||
139 | return; | ||
140 | } | ||
141 | // Calculate and display | ||
142 | calcBip32RootKeyFromBase58(rootKeyBase58); | ||
143 | calcForDerivationPath(); | ||
144 | hidePending(); | ||
145 | } | ||
146 | |||
147 | function calcForDerivationPath() { | ||
148 | showPending(); | ||
149 | hideValidationError(); | ||
96 | // Get the derivation path | 150 | // Get the derivation path |
97 | var derivationPath = getDerivationPath(); | 151 | var derivationPath = getDerivationPath(); |
98 | var errorText = findDerivationPathErrors(derivationPath); | 152 | var errorText = findDerivationPathErrors(derivationPath); |
@@ -100,8 +154,7 @@ | |||
100 | showValidationError(errorText); | 154 | showValidationError(errorText); |
101 | return; | 155 | return; |
102 | } | 156 | } |
103 | // Calculate and display | 157 | calcBip32ExtendedKey(derivationPath); |
104 | calcBip32Seed(phrase, passphrase, derivationPath); | ||
105 | displayBip32Info(); | 158 | displayBip32Info(); |
106 | hidePending(); | 159 | hidePending(); |
107 | } | 160 | } |
@@ -148,9 +201,16 @@ | |||
148 | return words; | 201 | return words; |
149 | } | 202 | } |
150 | 203 | ||
151 | function calcBip32Seed(phrase, passphrase, path) { | 204 | function calcBip32RootKeyFromSeed(phrase, passphrase) { |
152 | seed = mnemonic.toSeed(phrase, passphrase); | 205 | seed = mnemonic.toSeed(phrase, passphrase); |
153 | bip32RootKey = bitcoin.HDNode.fromSeedHex(seed, network); | 206 | bip32RootKey = bitcoin.HDNode.fromSeedHex(seed, network); |
207 | } | ||
208 | |||
209 | function calcBip32RootKeyFromBase58(rootKeyBase58) { | ||
210 | bip32RootKey = bitcoin.HDNode.fromBase58(rootKeyBase58); | ||
211 | } | ||
212 | |||
213 | function calcBip32ExtendedKey(path) { | ||
154 | bip32ExtendedKey = bip32RootKey; | 214 | bip32ExtendedKey = bip32RootKey; |
155 | // Derive the key from the path | 215 | // Derive the key from the path |
156 | var pathBits = path.split("/"); | 216 | var pathBits = path.split("/"); |
@@ -213,6 +273,16 @@ | |||
213 | return false; | 273 | return false; |
214 | } | 274 | } |
215 | 275 | ||
276 | function validateRootKey(rootKeyBase58) { | ||
277 | try { | ||
278 | bitcoin.HDNode.fromBase58(rootKeyBase58); | ||
279 | } | ||
280 | catch (e) { | ||
281 | return "Invalid root key"; | ||
282 | } | ||
283 | return ""; | ||
284 | } | ||
285 | |||
216 | function getDerivationPath() { | 286 | function getDerivationPath() { |
217 | if (DOM.bip44tab.hasClass("active")) { | 287 | if (DOM.bip44tab.hasClass("active")) { |
218 | var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44); | 288 | var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44); |
@@ -299,16 +369,27 @@ | |||
299 | 369 | ||
300 | function TableRow(index) { | 370 | function TableRow(index) { |
301 | 371 | ||
372 | var useHardenedAddresses = DOM.hardenedAddresses.prop("checked"); | ||
373 | |||
302 | function init() { | 374 | function init() { |
303 | calculateValues(); | 375 | calculateValues(); |
304 | } | 376 | } |
305 | 377 | ||
306 | function calculateValues() { | 378 | function calculateValues() { |
307 | setTimeout(function() { | 379 | setTimeout(function() { |
308 | var key = bip32ExtendedKey.derive(index); | 380 | var key = ""; |
381 | if (useHardenedAddresses) { | ||
382 | key = bip32ExtendedKey.deriveHardened(index); | ||
383 | } | ||
384 | else { | ||
385 | key = bip32ExtendedKey.derive(index); | ||
386 | } | ||
309 | var address = key.getAddress().toString(); | 387 | var address = key.getAddress().toString(); |
310 | var privkey = key.privKey.toWIF(network); | 388 | var privkey = key.privKey.toWIF(network); |
311 | var indexText = getDerivationPath() + "/" + index; | 389 | var indexText = getDerivationPath() + "/" + index; |
390 | if (useHardenedAddresses) { | ||
391 | indexText = indexText + "'"; | ||
392 | } | ||
312 | addAddressToList(indexText, address, privkey); | 393 | addAddressToList(indexText, address, privkey); |
313 | }, 50) | 394 | }, 50) |
314 | } | 395 | } |