diff options
author | Ian Coleman <coleman.ian@gmail.com> | 2016-11-03 16:34:56 +1100 |
---|---|---|
committer | Ian Coleman <coleman.ian@gmail.com> | 2016-11-04 15:14:13 +1100 |
commit | c6624d51f4e5607202e48903352574c47571baab (patch) | |
tree | ee57075575c8f9b88e13eb7efff083bb9fa2b39c /src/js/index.js | |
parent | d737abf6809622228faf7d5fe54101e2d87d72a4 (diff) | |
download | BIP39-c6624d51f4e5607202e48903352574c47571baab.tar.gz BIP39-c6624d51f4e5607202e48903352574c47571baab.tar.zst BIP39-c6624d51f4e5607202e48903352574c47571baab.zip |
Entropy can be supplied by user
Diffstat (limited to 'src/js/index.js')
-rw-r--r-- | src/js/index.js | 106 |
1 files changed, 105 insertions, 1 deletions
diff --git a/src/js/index.js b/src/js/index.js index 0e4cc05..cd7f281 100644 --- a/src/js/index.js +++ b/src/js/index.js | |||
@@ -14,14 +14,20 @@ | |||
14 | var showPubKey = true; | 14 | var showPubKey = true; |
15 | var showPrivKey = true; | 15 | var showPrivKey = true; |
16 | 16 | ||
17 | var entropyChangeTimeoutEvent = null; | ||
17 | var phraseChangeTimeoutEvent = null; | 18 | var phraseChangeTimeoutEvent = null; |
18 | var rootKeyChangedTimeoutEvent = null; | 19 | var rootKeyChangedTimeoutEvent = null; |
19 | 20 | ||
20 | var DOM = {}; | 21 | var DOM = {}; |
21 | DOM.network = $(".network"); | 22 | DOM.network = $(".network"); |
22 | DOM.phraseNetwork = $("#network-phrase"); | 23 | DOM.phraseNetwork = $("#network-phrase"); |
24 | DOM.useEntropy = $(".use-entropy"); | ||
25 | DOM.entropyContainer = $(".entropy-container"); | ||
26 | DOM.entropy = $(".entropy"); | ||
27 | DOM.entropyError = $(".entropy-error"); | ||
23 | DOM.phrase = $(".phrase"); | 28 | DOM.phrase = $(".phrase"); |
24 | DOM.passphrase = $(".passphrase"); | 29 | DOM.passphrase = $(".passphrase"); |
30 | DOM.generateContainer = $(".generate-container"); | ||
25 | DOM.generate = $(".generate"); | 31 | DOM.generate = $(".generate"); |
26 | DOM.seed = $(".seed"); | 32 | DOM.seed = $(".seed"); |
27 | DOM.rootKey = $(".root-key"); | 33 | DOM.rootKey = $(".root-key"); |
@@ -53,6 +59,8 @@ | |||
53 | function init() { | 59 | function init() { |
54 | // Events | 60 | // Events |
55 | DOM.network.on("change", networkChanged); | 61 | DOM.network.on("change", networkChanged); |
62 | DOM.useEntropy.on("change", setEntropyVisibility); | ||
63 | DOM.entropy.on("input", delayedEntropyChanged); | ||
56 | DOM.phrase.on("input", delayedPhraseChanged); | 64 | DOM.phrase.on("input", delayedPhraseChanged); |
57 | DOM.passphrase.on("input", delayedPhraseChanged); | 65 | DOM.passphrase.on("input", delayedPhraseChanged); |
58 | DOM.generate.on("click", generateClicked); | 66 | DOM.generate.on("click", generateClicked); |
@@ -89,6 +97,21 @@ | |||
89 | } | 97 | } |
90 | } | 98 | } |
91 | 99 | ||
100 | function setEntropyVisibility() { | ||
101 | if (isUsingOwnEntropy()) { | ||
102 | DOM.entropyContainer.removeClass("hidden"); | ||
103 | DOM.generateContainer.addClass("hidden"); | ||
104 | DOM.phrase.prop("readonly", true); | ||
105 | DOM.entropy.focus(); | ||
106 | entropyChanged(); | ||
107 | } | ||
108 | else { | ||
109 | DOM.entropyContainer.addClass("hidden"); | ||
110 | DOM.generateContainer.removeClass("hidden"); | ||
111 | DOM.phrase.prop("readonly", false); | ||
112 | } | ||
113 | } | ||
114 | |||
92 | function delayedPhraseChanged() { | 115 | function delayedPhraseChanged() { |
93 | hideValidationError(); | 116 | hideValidationError(); |
94 | showPending(); | 117 | showPending(); |
@@ -116,6 +139,20 @@ | |||
116 | hidePending(); | 139 | hidePending(); |
117 | } | 140 | } |
118 | 141 | ||
142 | function delayedEntropyChanged() { | ||
143 | hideValidationError(); | ||
144 | showPending(); | ||
145 | if (entropyChangeTimeoutEvent != null) { | ||
146 | clearTimeout(entropyChangeTimeoutEvent); | ||
147 | } | ||
148 | entropyChangeTimeoutEvent = setTimeout(entropyChanged, 400); | ||
149 | } | ||
150 | |||
151 | function entropyChanged() { | ||
152 | setMnemonicFromEntropy(); | ||
153 | phraseChanged(); | ||
154 | } | ||
155 | |||
119 | function delayedRootKeyChanged() { | 156 | function delayedRootKeyChanged() { |
120 | // Warn if there is an existing mnemonic or passphrase. | 157 | // Warn if there is an existing mnemonic or passphrase. |
121 | if (DOM.phrase.val().length > 0 || DOM.passphrase.val().length > 0) { | 158 | if (DOM.phrase.val().length > 0 || DOM.passphrase.val().length > 0) { |
@@ -168,6 +205,9 @@ | |||
168 | } | 205 | } |
169 | 206 | ||
170 | function generateClicked() { | 207 | function generateClicked() { |
208 | if (isUsingOwnEntropy()) { | ||
209 | return; | ||
210 | } | ||
171 | clearDisplay(); | 211 | clearDisplay(); |
172 | showPending(); | 212 | showPending(); |
173 | setTimeout(function() { | 213 | setTimeout(function() { |
@@ -599,7 +639,12 @@ | |||
599 | } | 639 | } |
600 | 640 | ||
601 | function getLanguageFromUrl() { | 641 | function getLanguageFromUrl() { |
602 | return window.location.hash.substring(1); | 642 | for (var language in WORDLISTS) { |
643 | if (window.location.hash.indexOf(language) > -1) { | ||
644 | return language; | ||
645 | } | ||
646 | } | ||
647 | return ""; | ||
603 | } | 648 | } |
604 | 649 | ||
605 | function setMnemonicLanguage() { | 650 | function setMnemonicLanguage() { |
@@ -650,6 +695,65 @@ | |||
650 | return phrase; | 695 | return phrase; |
651 | } | 696 | } |
652 | 697 | ||
698 | function isUsingOwnEntropy() { | ||
699 | return DOM.useEntropy.prop("checked"); | ||
700 | } | ||
701 | |||
702 | function setMnemonicFromEntropy() { | ||
703 | hideEntropyError(); | ||
704 | // Work out minimum base for entropy | ||
705 | var entropyStr = DOM.entropy.val(); | ||
706 | var entropy = Entropy.fromString(entropyStr); | ||
707 | if (entropy.hexStr.length == 0) { | ||
708 | return; | ||
709 | } | ||
710 | // Show entropy details | ||
711 | var extraBits = 32 - (entropy.binaryStr.length % 32); | ||
712 | var extraChars = Math.ceil(extraBits * Math.log(2) / Math.log(entropy.base.asInt)); | ||
713 | var strength = "an extremely weak"; | ||
714 | if (entropy.hexStr.length >= 8) { | ||
715 | strength = "a very weak"; | ||
716 | } | ||
717 | if (entropy.hexStr.length >= 12) { | ||
718 | strength = "a weak"; | ||
719 | } | ||
720 | if (entropy.hexStr.length >= 24) { | ||
721 | strength = "a strong"; | ||
722 | } | ||
723 | if (entropy.hexStr.length >= 32) { | ||
724 | strength = "a very strong"; | ||
725 | } | ||
726 | if (entropy.hexStr.length >= 40) { | ||
727 | strength = "an extremely strong"; | ||
728 | } | ||
729 | if (entropy.hexStr.length >=48) { | ||
730 | strength = "an even stronger" | ||
731 | } | ||
732 | var msg = "Have " + entropy.binaryStr.length + " bits of entropy, " + extraChars + " more " + entropy.base.str + " chars required to generate " + strength + " mnemonic: " + entropy.cleanStr; | ||
733 | showEntropyError(msg); | ||
734 | // Discard trailing entropy | ||
735 | var hexStr = entropy.hexStr.substring(0, Math.floor(entropy.hexStr.length / 8) * 8); | ||
736 | // Convert entropy string to numeric array | ||
737 | var entropyArr = []; | ||
738 | for (var i=0; i<hexStr.length / 2; i++) { | ||
739 | var entropyByte = parseInt(hexStr[i*2].concat(hexStr[i*2+1]), 16); | ||
740 | entropyArr.push(entropyByte) | ||
741 | } | ||
742 | // Convert entropy array to mnemonic | ||
743 | var phrase = mnemonic.toMnemonic(entropyArr); | ||
744 | // Set the mnemonic in the UI | ||
745 | DOM.phrase.val(phrase); | ||
746 | } | ||
747 | |||
748 | function hideEntropyError() { | ||
749 | DOM.entropyError.addClass("hidden"); | ||
750 | } | ||
751 | |||
752 | function showEntropyError(msg) { | ||
753 | DOM.entropyError.text(msg); | ||
754 | DOM.entropyError.removeClass("hidden"); | ||
755 | } | ||
756 | |||
653 | var networks = [ | 757 | var networks = [ |
654 | { | 758 | { |
655 | name: "Bitcoin", | 759 | name: "Bitcoin", |