]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blobdiff - bip39-standalone.html
Add client select
[perso/Immae/Projets/Cryptomonnaies/BIP39.git] / bip39-standalone.html
index 0fd48c4add7447e3f6459135b9fc3b5184ed9dbc..3b4f0f27de389dab22a7e9812380e3754fc69abd 100644 (file)
             .qr-image {
                 margin: 5px;
             }
-            .qr-hint {
+            .qr-hint,
+            .qr-warning {
                 padding: 2px;
+                max-width: 150px;
+            }
+            .more-info {
+                cursor: help;
+                border-bottom: 1px dashed #000;
+                text-decoration: none;
             }
         </style>
     </head>
                                     <div class="row">
                                         <label class="col-sm-3 control-label" data-translate>Word Count</label>
                                         <div class="word-count col-sm-3 form-control-static"></div>
-                                        <label class="col-sm-3 control-label" data-translate>Total Bits</label>
+                                        <label class="col-sm-3 control-label" data-translate><span class="more-info" data-translate-title title="Total bits of entropy may be less than indicated if any entropy event uses a weak source.">Total Bits</span></label>
                                         <div class="bits col-sm-3 form-control-static"></div>
                                     </div>
                                     <label class="col-sm-3 control-label" data-translate>Filtered Entropy</label>
                             random enough for the needs of this tool.
                         </span>
                     </p>
+                    <p>
+                        <strong><span data-translate>Do not store entropy.</span></strong>
+                    </p>
+                    <p>
+                        <span data-translate>Storing entropy (such as keeping a deck of cards in a specific shuffled order) is unreliable compared to storing a mnemonic.</span>
+                        <span data-translate>Instead of storing entropy, store the mnemonic generated from the entropy.</span>
+                        <span data-translate-html><a href="https://en.wikipedia.org/wiki/Steganography#Physical" target="_blank">Steganography</a> may be beneficial when storing the mnemonic.</span>
+                    </p>
                     <p>
                         <span data-translate-html>
                             The random mnemonic generator on this page uses a
                     <p>
                         <a href="https://bitcointalk.org/index.php?topic=311000.msg3345309#msg3345309" target="_blank" data-translate>You are not a good source of entropy.</a>
                     </p>
+                    <h3 data-translate>License</h3>
+                    <p>
+                    <span data-translate-html>Please refer to <a href="https://github.com/iancoleman/bip39/blob/master/LICENSE" target="_blank">the software license</a> for more detail.
+                    </span>
+                    </p>
+                    <p data-translate>The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.</p>
                 </div>
             </div>
 
         </div>
 
         <div class="qr-container hidden">
-            <div class="qr-hint bg-primary" data-translate>Click field to hide QR</div>
-            <div class="qr-hint bg-primary hidden" data-translate>Click field to show QR</div>
-            <div class="qr-image"></div>
+            <div class="qr-hint bg-primary hidden" data-translate>Click field to hide QR</div>
+            <div class="qr-hint bg-primary" data-translate>Click field to show QR</div>
+            <div class="qr-hider hidden">
+                <div class="qr-image"></div>
+                <div class="qr-warning bg-primary" data-translate>Caution: Scanner may keep history</div>
+            </div>
         </div>
 
         <div class="feedback-container">
@@ -14702,7 +14726,8 @@ sjcl.hash.sha256.prototype = {
 //
 //   <div data-translate>Test</div>
 //   <div data-translate-html><em>keep em tag</em></div>
-//   <input data-translate-placeholder placeholder="Example text">
+//   <input data-translate-placeholder placeholder="Example placeholder">
+//   <span data-translate-title title="Example title"></span>
 //
 // Obtain all the phrases to be translated via js debug console:
 //
@@ -14717,7 +14742,8 @@ sjcl.hash.sha256.prototype = {
 //   Translate.loadForeignPhrases("es", {
 //       "Test": "Test in Spanish",
 //       "<em>keep em tag</em>": "<em>keep em tag in Spanish</em>",
-//       "Example text": "Example text in Spanish"
+//       "Example placeholder": "Example placeholder in Spanish"
+//       "Example title": "Example title in Spanish"
 //   });
 //
 // In your UI put a listener for clicking on the Spanish button:
@@ -14768,10 +14794,21 @@ Translate = new (function() {
         },
     }
 
+    var title = {
+        selector: "[data-translate-title]",
+        getKey: function() {
+            return this.getAttribute("title").trim().replace(/\s+/g, " ");
+        },
+        setPhrase: function(p) {
+            this.setAttribute("title", p);
+        },
+    }
+
     // Get elements to be translated
     var allEls = getEls(text)
         .concat(getEls(html))
-        .concat(getEls(placeholder));
+        .concat(getEls(placeholder))
+        .concat(getEls(title));
 
     // Provides access to phrases from a non-default language.
     // See phrases_en.js for example usage.
@@ -18555,15 +18592,12 @@ window.Entropy = new (function() {
         // Create a normalized string of the selected cards
         var normalizedCards = cards.join("").toUpperCase();
         // Convert to binary using the SHA256 hash of the normalized cards.
-        // If the number of bits is more than 256, multiple rounds of hashing
+        // If the number of bits is more than 256, multiple hashes
         // are used until the required number of bits is reached.
         var entropyBin = "";
         var iterations = 0;
         while (entropyBin.length < numberOfBits) {
-            var hashedCards = sjcl.hash.sha256.hash(normalizedCards);
-            for (var j=0; j<iterations; j++) {
-                hashedCards = sjcl.hash.sha256.hash(hashedCards);
-            }
+            var hashedCards = sjcl.hash.sha256.hash(normalizedCards + ":" + iterations);
             var hashHex = sjcl.codec.hex.fromBits(hashedCards);
             for (var i=0; i<hashHex.length; i++) {
                 var decimal = parseInt(hashHex[i], 16);
@@ -18614,7 +18648,7 @@ window.Entropy = new (function() {
     // mnemonics is populated as required by getLanguage
     var mnemonics = { "english": new Mnemonic("english") };
     var mnemonic = mnemonics["english"];
-    var seed = null
+    var seed = null;
     var bip32RootKey = null;
     var bip32ExtendedKey = null;
     var network = bitcoin.networks.bitcoin;
@@ -18624,12 +18658,14 @@ window.Entropy = new (function() {
     var showAddress = true;
     var showPubKey = true;
     var showPrivKey = true;
-    var showQr = true;
+    var showQr = false;
 
     var entropyChangeTimeoutEvent = null;
     var phraseChangeTimeoutEvent = null;
     var rootKeyChangedTimeoutEvent = null;
 
+    var generationProcesses = [];
+
     var DOM = {};
     DOM.network = $(".network");
     DOM.phraseNetwork = $("#network-phrase");
@@ -18678,6 +18714,7 @@ window.Entropy = new (function() {
     DOM.privateKeyToggle = $(".private-key-toggle");
     DOM.languages = $(".languages a");
     DOM.qrContainer = $(".qr-container");
+    DOM.qrHider = DOM.qrContainer.find(".qr-hider");
     DOM.qrImage = DOM.qrContainer.find(".qr-image");
     DOM.qrHint = DOM.qrContainer.find(".qr-hint");
     DOM.showQrEls = $("[data-show-qr]");
@@ -18838,11 +18875,11 @@ window.Entropy = new (function() {
         // Calculate and display
         calcBip32RootKeyFromBase58(rootKeyBase58);
         calcForDerivationPath();
-        hidePending();
     }
 
     function calcForDerivationPath() {
         showPending();
+        clearAddressesList();
         hideValidationError();
         // Get the derivation path
         var derivationPath = getDerivationPath();
@@ -18934,6 +18971,10 @@ window.Entropy = new (function() {
     }
 
     function calcBip32ExtendedKey(path) {
+        // Check there's a root key to derive from
+        if (!bip32RootKey) {
+            return bip32RootKey;
+        }
         var extendedKey = bip32RootKey;
         // Derive the key from the path
         var pathBits = path.split("/");
@@ -18944,7 +18985,12 @@ window.Entropy = new (function() {
                 continue;
             }
             var hardened = bit[bit.length-1] == "'";
-            if (hardened) {
+            var isPriv = "privKey" in extendedKey;
+            var invalidDerivationPath = hardened && !isPriv;
+            if (invalidDerivationPath) {
+                extendedKey = null;
+            }
+            else if (hardened) {
                 extendedKey = extendedKey.deriveHardened(index);
             }
             else {
@@ -19063,6 +19109,16 @@ window.Entropy = new (function() {
                 }
             }
         }
+        // Check root key exists or else derivation path is useless!
+        if (!bip32RootKey) {
+            return "No root key";
+        }
+        // Check no hardened derivation path when using xpub keys
+        var hardened = path.indexOf("'") > -1;
+        var isXpubkey = !("privKey" in bip32RootKey);
+        if (hardened && isXpubkey) {
+            return "Hardened derivation path is invalid with xpub key";
+        }
         return false;
     }
 
@@ -19089,7 +19145,11 @@ window.Entropy = new (function() {
         DOM.seed.val(seed);
         var rootKey = bip32RootKey.toBase58();
         DOM.rootKey.val(rootKey);
-        var extendedPrivKey = bip32ExtendedKey.toBase58();
+        var xprvkeyB58 = "NA";
+        if (bip32ExtendedKey.privKey) {
+            xprvkeyB58 = bip32ExtendedKey.toBase58();
+        }
+        var extendedPrivKey = xprvkeyB58;
         DOM.extendedPrivKey.val(extendedPrivKey);
         var extendedPubKey = bip32ExtendedKey.toBase58(false);
         DOM.extendedPubKey.val(extendedPubKey);
@@ -19099,14 +19159,28 @@ window.Entropy = new (function() {
     }
 
     function displayAddresses(start, total) {
-        for (var i=0; i<total; i++) {
-            var index = i + start;
-            new TableRow(index);
-        }
+        generationProcesses.push(new (function() {
+
+            var rows = [];
+
+            this.stop = function() {
+                for (var i=0; i<rows.length; i++) {
+                    rows[i].shouldGenerate = false;
+                }
+            }
+
+            for (var i=0; i<total; i++) {
+                var index = i + start;
+                rows.push(new TableRow(index));
+            }
+
+        })());
     }
 
     function TableRow(index) {
 
+        var self = this;
+        this.shouldGenerate = true;
         var useHardenedAddresses = DOM.hardenedAddresses.prop("checked");
 
         function init() {
@@ -19115,6 +19189,9 @@ window.Entropy = new (function() {
 
         function calculateValues() {
             setTimeout(function() {
+                if (!self.shouldGenerate) {
+                    return;
+                }
                 var key = "";
                 if (useHardenedAddresses) {
                     key = bip32ExtendedKey.deriveHardened(index);
@@ -19123,7 +19200,10 @@ window.Entropy = new (function() {
                     key = bip32ExtendedKey.derive(index);
                 }
                 var address = key.getAddress().toString();
-                var privkey = key.privKey.toWIF(network);
+                var privkey = "NA";
+                if (key.privKey) {
+                    privkey = key.privKey.toWIF(network);
+                }
                 var pubkey = key.pubKey.toHex();
                 var indexText = getDerivationPath() + "/" + index;
                 if (useHardenedAddresses) {
@@ -19162,6 +19242,14 @@ window.Entropy = new (function() {
 
     function clearAddressesList() {
         DOM.addresses.empty();
+        stopGenerating();
+    }
+
+    function stopGenerating() {
+        while (generationProcesses.length > 0) {
+            var generation = generationProcesses.shift();
+            generation.stop();
+        }
     }
 
     function clearKey() {
@@ -19231,6 +19319,9 @@ window.Entropy = new (function() {
         var closestWord = words[0];
         for (var i=0; i<words.length; i++) {
             var comparedTo = words[i];
+            if (comparedTo.indexOf(word) == 0) {
+                return comparedTo;
+            }
             var distance = Levenshtein.get(word, comparedTo);
             if (distance < minDistance) {
                 closestWord = comparedTo;
@@ -19397,7 +19488,7 @@ window.Entropy = new (function() {
             var hash = sjcl.hash.sha256.hash(entropy.cleanStr);
             var hex = sjcl.codec.hex.fromBits(hash);
             bits = BigInteger.parse(hex, 16).toString(2);
-            for (var i=0; i<256-bits.length; i++) {
+            while (bits.length % 256 != 0) {
                 bits = "0" + bits;
             }
             // Truncate hash to suit number of words
@@ -19557,7 +19648,10 @@ window.Entropy = new (function() {
             var size = 130;
             DOM.qrImage.qrcode({width: size, height: size, text: content});
             if (!showQr) {
-                DOM.qrImage.addClass("hidden");
+                DOM.qrHider.addClass("hidden");
+            }
+            else {
+                DOM.qrHider.removeClass("hidden");
             }
             DOM.qrContainer.removeClass("hidden");
         }
@@ -19570,7 +19664,7 @@ window.Entropy = new (function() {
 
     function toggleQr() {
         showQr = !showQr;
-        DOM.qrImage.toggleClass("hidden");
+        DOM.qrHider.toggleClass("hidden");
         DOM.qrHint.toggleClass("hidden");
     }