diff options
author | Ian Coleman <coleman.ian@gmail.com> | 2016-11-07 11:51:12 +1100 |
---|---|---|
committer | Ian Coleman <coleman.ian@gmail.com> | 2016-11-07 13:16:47 +1100 |
commit | 057722b034672d240eea2ff01a7a5a01a4706e00 (patch) | |
tree | daf3832605dadb2e9403468570447d8a54562a20 | |
parent | 52e6eb81c8e464e12cea1ffc75104ca726daaa1a (diff) | |
download | BIP39-057722b034672d240eea2ff01a7a5a01a4706e00.tar.gz BIP39-057722b034672d240eea2ff01a7a5a01a4706e00.tar.zst BIP39-057722b034672d240eea2ff01a7a5a01a4706e00.zip |
Blank entropy does not generate addresses
-rw-r--r-- | src/js/index.js | 36 | ||||
-rw-r--r-- | tests.js | 210 |
2 files changed, 176 insertions, 70 deletions
diff --git a/src/js/index.js b/src/js/index.js index cd7f281..1cc77d3 100644 --- a/src/js/index.js +++ b/src/js/index.js | |||
@@ -109,6 +109,7 @@ | |||
109 | DOM.entropyContainer.addClass("hidden"); | 109 | DOM.entropyContainer.addClass("hidden"); |
110 | DOM.generateContainer.removeClass("hidden"); | 110 | DOM.generateContainer.removeClass("hidden"); |
111 | DOM.phrase.prop("readonly", false); | 111 | DOM.phrase.prop("readonly", false); |
112 | hidePending(); | ||
112 | } | 113 | } |
113 | } | 114 | } |
114 | 115 | ||
@@ -149,8 +150,31 @@ | |||
149 | } | 150 | } |
150 | 151 | ||
151 | function entropyChanged() { | 152 | function entropyChanged() { |
153 | // If blank entropy, clear mnemonic, addresses, errors | ||
154 | if (DOM.entropy.val().trim().length == 0) { | ||
155 | clearDisplay(); | ||
156 | hideEntropyError(); | ||
157 | DOM.phrase.val(""); | ||
158 | showValidationError("Blank entropy"); | ||
159 | return; | ||
160 | } | ||
161 | // Get the current phrase to detect changes | ||
162 | var phrase = DOM.phrase.val(); | ||
163 | // Set the phrase from the entropy | ||
152 | setMnemonicFromEntropy(); | 164 | setMnemonicFromEntropy(); |
153 | phraseChanged(); | 165 | // Recalc addresses if the phrase has changed |
166 | var newPhrase = DOM.phrase.val(); | ||
167 | if (newPhrase != phrase) { | ||
168 | if (newPhrase.length == 0) { | ||
169 | clearDisplay(); | ||
170 | } | ||
171 | else { | ||
172 | phraseChanged(); | ||
173 | } | ||
174 | } | ||
175 | else { | ||
176 | hidePending(); | ||
177 | } | ||
154 | } | 178 | } |
155 | 179 | ||
156 | function delayedRootKeyChanged() { | 180 | function delayedRootKeyChanged() { |
@@ -311,10 +335,13 @@ | |||
311 | } | 335 | } |
312 | 336 | ||
313 | function findPhraseErrors(phrase) { | 337 | function findPhraseErrors(phrase) { |
314 | // TODO make this right | ||
315 | // Preprocess the words | 338 | // Preprocess the words |
316 | phrase = mnemonic.normalizeString(phrase); | 339 | phrase = mnemonic.normalizeString(phrase); |
317 | var words = phraseToWordArray(phrase); | 340 | var words = phraseToWordArray(phrase); |
341 | // Detect blank phrase | ||
342 | if (words.length == 0) { | ||
343 | return "Blank mnemonic"; | ||
344 | } | ||
318 | // Check each word | 345 | // Check each word |
319 | for (var i=0; i<words.length; i++) { | 346 | for (var i=0; i<words.length; i++) { |
320 | var word = words[i]; | 347 | var word = words[i]; |
@@ -701,10 +728,11 @@ | |||
701 | 728 | ||
702 | function setMnemonicFromEntropy() { | 729 | function setMnemonicFromEntropy() { |
703 | hideEntropyError(); | 730 | hideEntropyError(); |
704 | // Work out minimum base for entropy | 731 | // Get entropy value |
705 | var entropyStr = DOM.entropy.val(); | 732 | var entropyStr = DOM.entropy.val(); |
733 | // Work out minimum base for entropy | ||
706 | var entropy = Entropy.fromString(entropyStr); | 734 | var entropy = Entropy.fromString(entropyStr); |
707 | if (entropy.hexStr.length == 0) { | 735 | if (entropy.binaryStr.length == 0) { |
708 | return; | 736 | return; |
709 | } | 737 | } |
710 | // Show entropy details | 738 | // Show entropy details |
@@ -75,6 +75,40 @@ function waitForFeedback(fn, maxTime) { | |||
75 | wait(); | 75 | wait(); |
76 | } | 76 | } |
77 | 77 | ||
78 | function waitForEntropyFeedback(fn, maxTime) { | ||
79 | if (!maxTime) { | ||
80 | maxTime = testMaxTime; | ||
81 | } | ||
82 | var origFeedback = page.evaluate(function() { | ||
83 | return $(".entropy-error").text(); | ||
84 | }); | ||
85 | var start = new Date().getTime(); | ||
86 | var wait = function keepWaiting() { | ||
87 | var now = new Date().getTime(); | ||
88 | var hasTimedOut = now - start > maxTime; | ||
89 | if (hasTimedOut) { | ||
90 | console.log("Test timed out"); | ||
91 | fn(); | ||
92 | return; | ||
93 | } | ||
94 | var feedback = page.evaluate(function() { | ||
95 | var feedback = $(".entropy-error"); | ||
96 | if (feedback.css("display") == "none") { | ||
97 | return ""; | ||
98 | } | ||
99 | return feedback.text(); | ||
100 | }); | ||
101 | var hasFinished = feedback != origFeedback; | ||
102 | if (hasFinished) { | ||
103 | fn(); | ||
104 | } | ||
105 | else { | ||
106 | setTimeout(keepWaiting, 100); | ||
107 | } | ||
108 | } | ||
109 | wait(); | ||
110 | } | ||
111 | |||
78 | function next() { | 112 | function next() { |
79 | if (tests.length > 0) { | 113 | if (tests.length > 0) { |
80 | var testsStr = tests.length == 1 ? "test" : "tests"; | 114 | var testsStr = tests.length == 1 ? "test" : "tests"; |
@@ -2146,7 +2180,7 @@ page.open(url, function(status) { | |||
2146 | $(".entropy").val(entropy).trigger("input"); | 2180 | $(".entropy").val(entropy).trigger("input"); |
2147 | }); | 2181 | }); |
2148 | // check the actual entropy being used is shown | 2182 | // check the actual entropy being used is shown |
2149 | waitForGenerate(function() { | 2183 | waitForEntropyFeedback(function() { |
2150 | var expectedText = "AedEceAA"; | 2184 | var expectedText = "AedEceAA"; |
2151 | var entropyText = page.evaluate(function() { | 2185 | var entropyText = page.evaluate(function() { |
2152 | return $(".entropy-container").text(); | 2186 | return $(".entropy-container").text(); |
@@ -2169,7 +2203,7 @@ page.open(url, function(status) { | |||
2169 | $(".entropy").val("01").trigger("input"); | 2203 | $(".entropy").val("01").trigger("input"); |
2170 | }); | 2204 | }); |
2171 | // check the entropy is shown to be the correct type | 2205 | // check the entropy is shown to be the correct type |
2172 | waitForGenerate(function() { | 2206 | waitForEntropyFeedback(function() { |
2173 | var entropyText = page.evaluate(function() { | 2207 | var entropyText = page.evaluate(function() { |
2174 | return $(".entropy-container").text(); | 2208 | return $(".entropy-container").text(); |
2175 | }); | 2209 | }); |
@@ -2191,7 +2225,7 @@ page.open(url, function(status) { | |||
2191 | $(".entropy").val("012345").trigger("input"); | 2225 | $(".entropy").val("012345").trigger("input"); |
2192 | }); | 2226 | }); |
2193 | // check the entropy is shown to be the correct type | 2227 | // check the entropy is shown to be the correct type |
2194 | waitForGenerate(function() { | 2228 | waitForEntropyFeedback(function() { |
2195 | var entropyText = page.evaluate(function() { | 2229 | var entropyText = page.evaluate(function() { |
2196 | return $(".entropy-container").text(); | 2230 | return $(".entropy-container").text(); |
2197 | }); | 2231 | }); |
@@ -2213,7 +2247,7 @@ page.open(url, function(status) { | |||
2213 | $(".entropy").val("123456").trigger("input"); | 2247 | $(".entropy").val("123456").trigger("input"); |
2214 | }); | 2248 | }); |
2215 | // check the entropy is shown to be the correct type | 2249 | // check the entropy is shown to be the correct type |
2216 | waitForGenerate(function() { | 2250 | waitForEntropyFeedback(function() { |
2217 | var entropyText = page.evaluate(function() { | 2251 | var entropyText = page.evaluate(function() { |
2218 | return $(".entropy-container").text(); | 2252 | return $(".entropy-container").text(); |
2219 | }); | 2253 | }); |
@@ -2235,7 +2269,7 @@ page.open(url, function(status) { | |||
2235 | $(".entropy").val("789").trigger("input"); | 2269 | $(".entropy").val("789").trigger("input"); |
2236 | }); | 2270 | }); |
2237 | // check the entropy is shown to be the correct type | 2271 | // check the entropy is shown to be the correct type |
2238 | waitForGenerate(function() { | 2272 | waitForEntropyFeedback(function() { |
2239 | var entropyText = page.evaluate(function() { | 2273 | var entropyText = page.evaluate(function() { |
2240 | return $(".entropy-container").text(); | 2274 | return $(".entropy-container").text(); |
2241 | }); | 2275 | }); |
@@ -2257,7 +2291,7 @@ page.open(url, function(status) { | |||
2257 | $(".entropy").val("abcdef").trigger("input"); | 2291 | $(".entropy").val("abcdef").trigger("input"); |
2258 | }); | 2292 | }); |
2259 | // check the entropy is shown to be the correct type | 2293 | // check the entropy is shown to be the correct type |
2260 | waitForGenerate(function() { | 2294 | waitForEntropyFeedback(function() { |
2261 | var entropyText = page.evaluate(function() { | 2295 | var entropyText = page.evaluate(function() { |
2262 | return $(".entropy-container").text(); | 2296 | return $(".entropy-container").text(); |
2263 | }); | 2297 | }); |
@@ -2279,7 +2313,7 @@ page.open(url, function(status) { | |||
2279 | $(".entropy").val("123456").trigger("input"); | 2313 | $(".entropy").val("123456").trigger("input"); |
2280 | }); | 2314 | }); |
2281 | // check the entropy is shown as base 6, not as the original dice value | 2315 | // check the entropy is shown as base 6, not as the original dice value |
2282 | waitForGenerate(function() { | 2316 | waitForEntropyFeedback(function() { |
2283 | var entropyText = page.evaluate(function() { | 2317 | var entropyText = page.evaluate(function() { |
2284 | return $(".entropy-container").text(); | 2318 | return $(".entropy-container").text(); |
2285 | }); | 2319 | }); |
@@ -2299,58 +2333,52 @@ page.open(url, function(status) { | |||
2299 | // The number of bits of entropy accumulated is shown | 2333 | // The number of bits of entropy accumulated is shown |
2300 | function() { | 2334 | function() { |
2301 | page.open(url, function(status) { | 2335 | page.open(url, function(status) { |
2302 | var tests = { | 2336 | //[ entropy, bits ] |
2303 | "0000 0000 0000 0000 0000": "20", | 2337 | var tests = [ |
2304 | "0": "1", | 2338 | [ "0000 0000 0000 0000 0000", "20" ], |
2305 | "0000": "4", | 2339 | [ "0", "1" ], |
2306 | "6": "3", | 2340 | [ "0000", "4" ], |
2307 | "7": "3", | 2341 | [ "6", "3" ], |
2308 | "8": "4", | 2342 | [ "7", "3" ], |
2309 | "F": "4", | 2343 | [ "8", "4" ], |
2310 | "29": "5", | 2344 | [ "F", "4" ], |
2311 | "0A": "8", | 2345 | [ "29", "5" ], |
2312 | "1A": "8", // hex is always multiple of 4 bits of entropy | 2346 | [ "0A", "8" ], |
2313 | "2A": "8", | 2347 | [ "1A", "8" ], // hex is always multiple of 4 bits of entropy |
2314 | "4A": "8", | 2348 | [ "2A", "8" ], |
2315 | "8A": "8", | 2349 | [ "4A", "8" ], |
2316 | "FA": "8", | 2350 | [ "8A", "8" ], |
2317 | "000A": "16", | 2351 | [ "FA", "8" ], |
2318 | "2220": "10", | 2352 | [ "000A", "16" ], |
2319 | "2221": "9", // uses dice, so entropy is actually 1110 | 2353 | [ "2220", "10" ], |
2320 | "2227": "12", | 2354 | [ "2221", "9" ], // uses dice, so entropy is actually 1110 |
2321 | "222F": "16", | 2355 | [ "2227", "12" ], |
2322 | "FFFF": "16", | 2356 | [ "222F", "16" ], |
2323 | } | 2357 | [ "FFFF", "16" ], |
2324 | // Arrange tests in array so last one can be easily detected | 2358 | ] |
2325 | var entropys = []; | ||
2326 | var results = []; | ||
2327 | for (var entropy in tests) { | ||
2328 | entropys.push(entropy); | ||
2329 | results.push(tests[entropy]); | ||
2330 | } | ||
2331 | // use entropy | 2359 | // use entropy |
2332 | page.evaluate(function(e) { | 2360 | page.evaluate(function(e) { |
2333 | $(".use-entropy").prop("checked", true).trigger("change"); | 2361 | $(".use-entropy").prop("checked", true).trigger("change"); |
2334 | }); | 2362 | }); |
2335 | // Run each test | 2363 | // Run each test |
2336 | var nextTest = function runNextTest(i) { | 2364 | var nextTest = function runNextTest(i) { |
2337 | var entropy = entropys[i]; | 2365 | var entropy = tests[i][0]; |
2338 | var expected = results[i]; | 2366 | var expected = tests[i][1]; |
2339 | // set entropy | 2367 | // set entropy |
2340 | page.evaluate(function(e) { | 2368 | page.evaluate(function(e) { |
2341 | $(".addresses").empty(); // bit of a hack, but needed for waitForGenerate | ||
2342 | $(".entropy").val(e).trigger("input"); | 2369 | $(".entropy").val(e).trigger("input"); |
2343 | }, entropy); | 2370 | }, entropy); |
2344 | // check the number of bits of entropy is shown | 2371 | // check the number of bits of entropy is shown |
2345 | waitForGenerate(function() { | 2372 | waitForEntropyFeedback(function() { |
2346 | var entropyText = page.evaluate(function() { | 2373 | var entropyText = page.evaluate(function() { |
2347 | return $(".entropy-container").text(); | 2374 | return $(".entropy-error").text(); |
2348 | }); | 2375 | }); |
2349 | if (entropyText.indexOf("Have " + expected + " bits of entropy") == -1) { | 2376 | if (entropyText.indexOf("Have " + expected + " bits of entropy") == -1) { |
2350 | console.log("Accumulated entropy is not shown correctly for " + entropy); | 2377 | console.log("Accumulated entropy is not shown correctly for " + entropy); |
2378 | console.log(entropyText); | ||
2351 | fail(); | 2379 | fail(); |
2352 | } | 2380 | } |
2353 | var isLastTest = i == results.length - 1; | 2381 | var isLastTest = i == tests.length - 1; |
2354 | if (isLastTest) { | 2382 | if (isLastTest) { |
2355 | next(); | 2383 | next(); |
2356 | } | 2384 | } |
@@ -2372,7 +2400,7 @@ page.open(url, function(status) { | |||
2372 | $(".entropy").val("7654321").trigger("input"); | 2400 | $(".entropy").val("7654321").trigger("input"); |
2373 | }); | 2401 | }); |
2374 | // check the amount of additional entropy required is shown | 2402 | // check the amount of additional entropy required is shown |
2375 | waitForGenerate(function() { | 2403 | waitForEntropyFeedback(function() { |
2376 | var entropyText = page.evaluate(function() { | 2404 | var entropyText = page.evaluate(function() { |
2377 | return $(".entropy-container").text(); | 2405 | return $(".entropy-container").text(); |
2378 | }); | 2406 | }); |
@@ -2438,33 +2466,16 @@ page.open(url, function(status) { | |||
2438 | test = tests[i]; | 2466 | test = tests[i]; |
2439 | page.evaluate(function(e) { | 2467 | page.evaluate(function(e) { |
2440 | $(".addresses").empty(); | 2468 | $(".addresses").empty(); |
2469 | $(".phrase").val(""); | ||
2441 | $(".entropy").val(e).trigger("input"); | 2470 | $(".entropy").val(e).trigger("input"); |
2442 | }, test.entropy); | 2471 | }, test.entropy); |
2443 | waitForGenerate(function() { | 2472 | if (test.words == 0) { |
2444 | // check the strength of the current mnemonic | ||
2445 | var mnemonic = page.evaluate(function() { | 2473 | var mnemonic = page.evaluate(function() { |
2446 | return $(".phrase").val(); | 2474 | return $(".phrase").val(); |
2447 | }); | 2475 | }); |
2448 | if (test.words == 0) { | 2476 | if (mnemonic.length > 0) { |
2449 | if (mnemonic.length > 0) { | 2477 | console.log("Mnemonic length for " + test.nextStrength + " strength is not " + test.words); |
2450 | console.log("Mnemonic length for " + test.nextStrength + " strength is not " + test.words); | 2478 | console.log("Mnemonic: " + mnemonic); |
2451 | console.log("Mnemonic: " + mnemonic); | ||
2452 | fail(); | ||
2453 | } | ||
2454 | } | ||
2455 | else { | ||
2456 | if (mnemonic.split(" ").length != test.words) { | ||
2457 | console.log("Mnemonic length for " + test.nextStrength + " strength is not " + test.words); | ||
2458 | console.log("Mnemonic: " + mnemonic); | ||
2459 | fail(); | ||
2460 | } | ||
2461 | } | ||
2462 | // check the strength of the next mnemonic is shown | ||
2463 | var entropyText = page.evaluate(function() { | ||
2464 | return $(".entropy-container").text(); | ||
2465 | }); | ||
2466 | if (entropyText.indexOf("required to generate " + test.nextStrength + " mnemonic") == -1) { | ||
2467 | console.log("Strength indicator for " + test.nextStrength + " mnemonic is incorrect"); | ||
2468 | fail(); | 2479 | fail(); |
2469 | } | 2480 | } |
2470 | var isLastTest = i == tests.length - 1; | 2481 | var isLastTest = i == tests.length - 1; |
@@ -2474,7 +2485,35 @@ page.open(url, function(status) { | |||
2474 | else { | 2485 | else { |
2475 | runNextTest(i+1); | 2486 | runNextTest(i+1); |
2476 | } | 2487 | } |
2477 | }); | 2488 | } |
2489 | else { | ||
2490 | waitForGenerate(function() { | ||
2491 | // check the strength of the current mnemonic | ||
2492 | var mnemonic = page.evaluate(function() { | ||
2493 | return $(".phrase").val(); | ||
2494 | }); | ||
2495 | if (mnemonic.split(" ").length != test.words) { | ||
2496 | console.log("Mnemonic length for " + test.nextStrength + " strength is not " + test.words); | ||
2497 | console.log("Mnemonic: " + mnemonic); | ||
2498 | fail(); | ||
2499 | } | ||
2500 | // check the strength of the next mnemonic is shown | ||
2501 | var entropyText = page.evaluate(function() { | ||
2502 | return $(".entropy-container").text(); | ||
2503 | }); | ||
2504 | if (entropyText.indexOf("required to generate " + test.nextStrength + " mnemonic") == -1) { | ||
2505 | console.log("Strength indicator for " + test.nextStrength + " mnemonic is incorrect"); | ||
2506 | fail(); | ||
2507 | } | ||
2508 | var isLastTest = i == tests.length - 1; | ||
2509 | if (isLastTest) { | ||
2510 | next(); | ||
2511 | } | ||
2512 | else { | ||
2513 | runNextTest(i+1); | ||
2514 | } | ||
2515 | }); | ||
2516 | } | ||
2478 | } | 2517 | } |
2479 | nextTest(0); | 2518 | nextTest(0); |
2480 | }); | 2519 | }); |
@@ -2567,6 +2606,45 @@ page.open(url, function(status) { | |||
2567 | }); | 2606 | }); |
2568 | }, | 2607 | }, |
2569 | 2608 | ||
2609 | // Blank entropy does not generate mnemonic or addresses | ||
2610 | function() { | ||
2611 | page.open(url, function(status) { | ||
2612 | // use entropy | ||
2613 | page.evaluate(function() { | ||
2614 | $(".use-entropy").prop("checked", true).trigger("change"); | ||
2615 | $(".entropy").val("").trigger("input"); | ||
2616 | }); | ||
2617 | waitForFeedback(function() { | ||
2618 | // check there is no mnemonic | ||
2619 | var phrase = page.evaluate(function() { | ||
2620 | return $(".phrase").val(); | ||
2621 | }); | ||
2622 | if (phrase != "") { | ||
2623 | console.log("Blank entropy does not result in blank mnemonic"); | ||
2624 | console.log("Got: " + phrase); | ||
2625 | fail(); | ||
2626 | } | ||
2627 | // check there are no addresses displayed | ||
2628 | var addresses = page.evaluate(function() { | ||
2629 | return $(".address").length; | ||
2630 | }); | ||
2631 | if (addresses != 0) { | ||
2632 | console.log("Blank entropy does not result in zero addresses"); | ||
2633 | fail(); | ||
2634 | } | ||
2635 | // Check the feedback says 'blank entropy' | ||
2636 | var feedback = page.evaluate(function() { | ||
2637 | return $(".feedback").text(); | ||
2638 | }); | ||
2639 | if (feedback != "Blank entropy") { | ||
2640 | console.log("Blank entropy does not show feedback message"); | ||
2641 | fail(); | ||
2642 | } | ||
2643 | next(); | ||
2644 | }); | ||
2645 | }); | ||
2646 | }, | ||
2647 | |||
2570 | // If you wish to add more tests, do so here... | 2648 | // If you wish to add more tests, do so here... |
2571 | 2649 | ||
2572 | // Here is a blank test template | 2650 | // Here is a blank test template |