]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blobdiff - src/js/index.js
DOM.strength renamed DOM.generatedStrength
[perso/Immae/Projets/Cryptomonnaies/BIP39.git] / src / js / index.js
index 0e4cc052a4d704fa749bf9076c9bc68fc5145530..45db7b139861814e603903c68c5a583c5dd4fa6e 100644 (file)
     var showPubKey = true;
     var showPrivKey = true;
 
+    var entropyChangeTimeoutEvent = null;
     var phraseChangeTimeoutEvent = null;
     var rootKeyChangedTimeoutEvent = null;
 
     var DOM = {};
     DOM.network = $(".network");
     DOM.phraseNetwork = $("#network-phrase");
+    DOM.useEntropy = $(".use-entropy");
+    DOM.entropyContainer = $(".entropy-container");
+    DOM.entropy = $(".entropy");
+    DOM.entropyError = $(".entropy-error");
     DOM.phrase = $(".phrase");
     DOM.passphrase = $(".passphrase");
+    DOM.generateContainer = $(".generate-container");
     DOM.generate = $(".generate");
     DOM.seed = $(".seed");
     DOM.rootKey = $(".root-key");
@@ -37,7 +43,7 @@
     DOM.bip44coin = $("#bip44 .coin");
     DOM.bip44account = $("#bip44 .account");
     DOM.bip44change = $("#bip44 .change");
-    DOM.strength = $(".strength");
+    DOM.generatedStrength = $(".generate-container .strength");
     DOM.hardenedAddresses = $(".hardened-addresses");
     DOM.addresses = $(".addresses");
     DOM.rowsToAdd = $(".rows-to-add");
@@ -53,6 +59,8 @@
     function init() {
         // Events
         DOM.network.on("change", networkChanged);
+        DOM.useEntropy.on("change", setEntropyVisibility);
+        DOM.entropy.on("input", delayedEntropyChanged);
         DOM.phrase.on("input", delayedPhraseChanged);
         DOM.passphrase.on("input", delayedPhraseChanged);
         DOM.generate.on("click", generateClicked);
         }
     }
 
+    function setEntropyVisibility() {
+        if (isUsingOwnEntropy()) {
+            DOM.entropyContainer.removeClass("hidden");
+            DOM.generateContainer.addClass("hidden");
+            DOM.phrase.prop("readonly", true);
+            DOM.entropy.focus();
+            entropyChanged();
+        }
+        else {
+            DOM.entropyContainer.addClass("hidden");
+            DOM.generateContainer.removeClass("hidden");
+            DOM.phrase.prop("readonly", false);
+            hidePending();
+        }
+    }
+
     function delayedPhraseChanged() {
         hideValidationError();
         showPending();
         hidePending();
     }
 
+    function delayedEntropyChanged() {
+        hideValidationError();
+        showPending();
+        if (entropyChangeTimeoutEvent != null) {
+            clearTimeout(entropyChangeTimeoutEvent);
+        }
+        entropyChangeTimeoutEvent = setTimeout(entropyChanged, 400);
+    }
+
+    function entropyChanged() {
+        // If blank entropy, clear mnemonic, addresses, errors
+        if (DOM.entropy.val().trim().length == 0) {
+            clearDisplay();
+            hideEntropyError();
+            DOM.phrase.val("");
+            showValidationError("Blank entropy");
+            return;
+        }
+        // Get the current phrase to detect changes
+        var phrase = DOM.phrase.val();
+        // Set the phrase from the entropy
+        setMnemonicFromEntropy();
+        // Recalc addresses if the phrase has changed
+        var newPhrase = DOM.phrase.val();
+        if (newPhrase != phrase) {
+            if (newPhrase.length == 0) {
+                clearDisplay();
+            }
+            else {
+                phraseChanged();
+            }
+        }
+        else {
+            hidePending();
+        }
+    }
+
     function delayedRootKeyChanged() {
         // Warn if there is an existing mnemonic or passphrase.
         if (DOM.phrase.val().length > 0 || DOM.passphrase.val().length > 0) {
     }
 
     function generateClicked() {
+        if (isUsingOwnEntropy()) {
+            return;
+        }
         clearDisplay();
         showPending();
         setTimeout(function() {
             showValidationError(errorText);
             return;
         }
-        var numWords = parseInt(DOM.strength.val());
+        var numWords = parseInt(DOM.generatedStrength.val());
         var strength = numWords / 3 * 32;
         var words = mnemonic.generate(strength);
         DOM.phrase.val(words);
     }
 
     function findPhraseErrors(phrase) {
-        // TODO make this right
         // Preprocess the words
         phrase = mnemonic.normalizeString(phrase);
         var words = phraseToWordArray(phrase);
+        // Detect blank phrase
+        if (words.length == 0) {
+            return "Blank mnemonic";
+        }
         // Check each word
         for (var i=0; i<words.length; i++) {
             var word = words[i];
     }
 
     function getLanguageFromUrl() {
-        return window.location.hash.substring(1);
+        for (var language in WORDLISTS) {
+            if (window.location.hash.indexOf(language) > -1) {
+                return language;
+            }
+        }
+        return "";
     }
 
     function setMnemonicLanguage() {
         return phrase;
     }
 
+    function isUsingOwnEntropy() {
+        return DOM.useEntropy.prop("checked");
+    }
+
+    function setMnemonicFromEntropy() {
+        hideEntropyError();
+        // Get entropy value
+        var entropyStr = DOM.entropy.val();
+        // Work out minimum base for entropy
+        var entropy = Entropy.fromString(entropyStr);
+        if (entropy.binaryStr.length == 0) {
+            return;
+        }
+        // Show entropy details
+        var extraBits = 32 - (entropy.binaryStr.length % 32);
+        var extraChars = Math.ceil(extraBits * Math.log(2) / Math.log(entropy.base.asInt));
+        var words = Math.floor(entropy.binaryStr.length / 32) * 3;
+        var strength = "an extremely weak";
+        if (words >= 3) {
+            strength = "a very weak";
+        }
+        if (words >= 6) {
+            strength = "a weak";
+        }
+        if (words >= 9) {
+            strength = "a strong";
+        }
+        if (words >= 12) {
+            strength = "a very strong";
+        }
+        if (words >= 15) {
+            strength = "an extremely strong";
+        }
+        if (words >= 18) {
+            strength = "an even stronger"
+        }
+        var msg = "Have " + entropy.binaryStr.length + " bits of entropy, " + extraChars + " more " + entropy.base.str + " chars required to generate " + strength + " mnemonic: " + entropy.cleanStr;
+        showEntropyError(msg);
+        // Discard trailing entropy
+        var bitsToUse = Math.floor(entropy.binaryStr.length / 32) * 32;
+        var binaryStr = entropy.binaryStr.substring(0, bitsToUse);
+        // Convert entropy string to numeric array
+        var entropyArr = [];
+        for (var i=0; i<binaryStr.length / 8; i++) {
+            var byteAsBits = binaryStr.substring(i*8, i*8+8);
+            var entropyByte = parseInt(byteAsBits, 2);
+            entropyArr.push(entropyByte)
+        }
+        // Convert entropy array to mnemonic
+        var phrase = mnemonic.toMnemonic(entropyArr);
+        // Set the mnemonic in the UI
+        DOM.phrase.val(phrase);
+    }
+
+    function hideEntropyError() {
+        DOM.entropyError.addClass("hidden");
+    }
+
+    function showEntropyError(msg) {
+        DOM.entropyError.text(msg);
+        DOM.entropyError.removeClass("hidden");
+    }
+
     var networks = [
         {
             name: "Bitcoin",